🔐1auth SDK Docs
Back to documentation

Dialog API Reference

Reference

PostMessage 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

CodeDescription
USER_REJECTEDUser closed dialog or clicked reject
SIGNING_FAILEDWebAuthn signing operation failed
EXPIREDSigning request has expired
INVALID_REQUESTMalformed request data
NETWORK_ERRORNetwork communication error
UNKNOWNUnexpected 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