How Login Works
When a user calls login(), three things happen in sequence: the SDK injects an iframe, sends an initialization message, and waits for a reply. This page walks through each step so you know exactly what your users will see — and what happens under the hood.
The iframe
Section titled “The iframe”The SDK creates an <iframe> element and appends it to document.body. The iframe is:
- Full-screen with a semi-transparent backdrop
- Positioned with
z-index: 99999by default (configurable) - Loaded from
https://d1p4mbm3uswucw.cloudfront.net/widget.html
The iframe runs on a different origin from your application. This is the key security boundary. Your JavaScript cannot access the iframe’s DOM, its memory, or anything it stores. The only way the two can communicate is through postMessage — and the SDK validates the origin of every message.
The message protocol
Section titled “The message protocol”Once the iframe loads, it sends a WIDGET_READY message. The SDK responds with an INIT message containing your API key:
Your App → iframe: { type: "INIT", payload: { apiKey: "..." } }The widget then presents the email/password login form. When the user authenticates successfully, the widget responds:
iframe → Your App: { type: "WALLET_READY", payload: { address: "0x...", email: "..." } }At this point, the SDK hides the iframe, saves the wallet info, transitions to the "connected" state, and resolves the login() promise.
If authentication fails, the widget sends AUTH_ERROR instead, and login() rejects with a WidgetError.
The KMS key
Section titled “The KMS key”The user’s private key is generated inside AWS KMS and never leaves it. When the user authenticates, the widget obtains a short-lived access token. That token allows the widget to request signatures from KMS on the user’s behalf — but only while the token is valid. The token is stored inside the iframe’s memory and is never sent to your application.
Login timeout
Section titled “Login timeout”By default, the SDK waits up to 5 minutes for the user to complete login. If they take longer, login() rejects with a SigningTimeoutError. You can configure this with the loginTimeout option.
Already logged in
Section titled “Already logged in”If login() is called when the user is already authenticated, it returns the cached wallet info immediately without opening the widget. You can check client.isLoggedIn first if you want to avoid calling login() unnecessarily.
What the user sees
Section titled “What the user sees”- A full-screen overlay appears with a centered widget
- The user enters their email and password
- If it’s their first time, they may be asked to verify their email
- On success, the overlay disappears and your app receives the wallet info