Dialog API Reference
ReferencePostMessage protocol documentation for the dialog system.
Overview
The 1auth SDK communicates with the dialog iframe using the postMessage API. This document describes the message protocol for advanced integrations.
Message Flow
Parent (SDK) Dialog (iframe)
│ │
│ ◀────── PASSKEY_READY ────────── │ Dialog loaded
│ │
│ ─────── PASSKEY_INIT ──────────▶ │ Send signing data
│ │
│ ◀────── PASSKEY_RESIZE ───────── │ Resize dialog
│ │
│ ◀───── PASSKEY_SIGNING_RESULT ── │ Return signature
│ │
│ ◀────── PASSKEY_CLOSE ────────── │ Close dialog
│ │Message Types
PASSKEY_READY
Sent by the dialog when it's ready to receive signing data.
Direction: Dialog → Parent
{
type: "PASSKEY_READY"
}PASSKEY_INIT
Sent by the parent to initialize the signing flow.
Direction: Parent → Dialog
For Transaction Signing:
{
type: "PASSKEY_INIT",
mode: "iframe" | "popup",
// Transaction data
calls: Array<{
to: string; // Target contract
data?: string; // Calldata
value?: string; // Wei value
}>,
chainId: number,
// Optional pre-decoded transaction details
transaction?: {
actions: Array<{
type: "send" | "approve" | "swap" | "mint" | "custom",
label: string,
sublabel?: string,
amount?: string,
}>,
fees?: {
estimated: string,
network: { name: string },
},
},
// Signing challenge (required)
challenge: string,
username?: string,
}For Message Signing:
{
type: "PASSKEY_INIT",
mode: "iframe" | "popup",
// Message to sign (instead of calls)
message: string,
// Common fields
challenge: string, // Signing challenge
username?: string,
description?: string, // Description for user
metadata?: Record<string, unknown>,
}PASSKEY_SIGNING_RESULT
Sent by the dialog after signing completes or fails.
Direction: Dialog → Parent
{
type: "PASSKEY_SIGNING_RESULT",
success: boolean,
data?: {
signature: {
authenticatorData: string,
clientDataJSON: string,
r: string,
s: string,
challengeIndex: number,
typeIndex: number,
topOrigin: string | null,
},
passkey?: {
credentialId: string,
publicKeyX: string,
publicKeyY: string,
},
calls?: Array<{...}>, // Echo back for transaction signing
},
error?: {
code: "USER_REJECTED" | "SIGNING_FAILED" | "EXPIRED" | "UNKNOWN",
message: string,
},
}PASSKEY_RESIZE
Request to resize the dialog container.
Direction: Dialog → Parent
{
type: "PASSKEY_RESIZE",
height: number,
width?: number, // Optional width change
}PASSKEY_CLOSE
Request to close the dialog.
Direction: Dialog → Parent
{
type: "PASSKEY_CLOSE"
}PASSKEY_DISCONNECT
Request to disconnect/logout the user.
Direction: Dialog → Parent
{
type: "PASSKEY_DISCONNECT"
}TRANSACTION_STATUS
Update transaction status (for intent flows).
Direction: Parent → Dialog
{
type: "TRANSACTION_STATUS",
status: "processing" | "confirmed" | "failed",
transactionHash?: string,
}Custom Integration Example
For advanced use cases where you want to control the dialog directly:
// Create iframe
const iframe = document.createElement('iframe');
iframe.src = 'https://auth.example.com/dialog/sign?mode=iframe';
iframe.allow = 'publickey-credentials-get *; publickey-credentials-create *';
document.body.appendChild(iframe);
// Listen for messages
window.addEventListener('message', (event) => {
// Always validate origin
if (event.origin !== 'https://auth.example.com') return;
// Handle ready signal
if (event.data.type === 'PASSKEY_READY') {
// Send signing data
iframe.contentWindow.postMessage({
type: 'PASSKEY_INIT',
mode: 'iframe',
message: 'Sign this message',
challenge: 'unique-challenge-string',
username: 'alice',
description: 'Verify your identity',
}, 'https://auth.example.com');
}
// Handle signing result
if (event.data.type === 'PASSKEY_SIGNING_RESULT') {
if (event.data.success) {
console.log('Signature:', event.data.data.signature);
// Verify signature server-side
} else {
console.error('Error:', event.data.error);
}
iframe.remove();
}
// Handle resize
if (event.data.type === 'PASSKEY_RESIZE') {
iframe.style.height = `${event.data.height}px`;
}
// Handle close request
if (event.data.type === 'PASSKEY_CLOSE') {
iframe.remove();
}
});Security Considerations
1. Always Validate Message Origin
window.addEventListener('message', (event) => {
// CRITICAL: Only accept messages from expected origin
if (event.origin !== EXPECTED_DIALOG_ORIGIN) {
return;
}
// Process message...
});2. Use Unique Challenges
Generate unique, short-lived challenges for each signing request:
const challenge = crypto.randomUUID();
// Or for more entropy:
const challenge = `${Date.now()}-${crypto.randomUUID()}`;3. Verify Signatures Server-Side
Never trust client-side signature verification alone:
// Client
const result = await client.signMessage({ ... });
// Send to your backend
const verified = await fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({
signature: result.signature,
challenge: originalChallenge,
username: result.username,
}),
});4. Use Sandbox Attributes
When embedding iframes, use appropriate sandbox attributes:
<iframe
src="..."
sandbox="allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
allow="publickey-credentials-get *; publickey-credentials-create *"
></iframe>Error Codes
| Code | Description |
|---|---|
USER_REJECTED | User closed dialog or clicked reject |
SIGNING_FAILED | WebAuthn signing operation failed |
EXPIRED | Signing request has expired |
INVALID_REQUEST | Malformed request data |
NETWORK_ERROR | Network communication error |
UNKNOWN | Unexpected error |
Notes
- The SDK handles all of this automatically - use custom integration only when needed
- Dialog theme can be customized via URL parameters:
?theme=dark&accent=%236366f1 - The dialog automatically resizes based on content