Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

App-origin passkeys

App-origin mode creates and uses passkeys in your application's top-level page. You can keep the default—one separate passkey and smart account per hostname—or configure one RP ID plus exact server-authorized rpOrigins so several same-site deployment origins share one passkey/account namespace.

A configured clientId defaults the SDK to app-origin mode. It identifies your registered application, but it is not itself the WebAuthn RP ID or browser origin.

Choose your WebAuthn mode

App-originExperimental cross-origin
DefaultYesNo
Ceremony runs inYour top-level pageA 1auth iframe or popup
Passkey RPYour page hostname, or a configured webauthn.rpIdThe 1auth provider RP
Account namespacehttps://<rpId> (hostname only, ports excluded)The exact calling origin, non-default port included
getSession()Verified with the providerLocally persisted state, not server-verified
Popup, redirect, and inline-embed signingNoYes, through the experimental_* methods
Traditional EOA signerNoYes, opted in explicitly
openAccountDialog()No (explicit unsupported result)Yes

Use app-origin unless you need a capability only cross-origin provides.

Switching modes selects a different credential, signer, and smart account. 1auth does not migrate accounts between namespaces and never switches modes on its own.

RP ID and RP origin, in plain language

WebAuthn binds every passkey to two related values:

  • RP ID: the passkey's website namespace. It is a hostname with no https:// and no port, for example example.com. A passkey created for one RP ID cannot silently be used for another.
  • RP origin: the exact page that runs the ceremony, including the scheme and any non-default port, for example https://checkout.example.com. The browser writes this value into the signed WebAuthn response; the SDK cannot forge or replace it.

For a page at https://checkout.example.com, the default is:

RP ID:       checkout.example.com
RP origin:   https://checkout.example.com
Account key: https://checkout.example.com

With a configured shared RP ID of example.com, the same page uses:

RP ID:       example.com
RP origin:   https://checkout.example.com
Account key: https://example.com

The RP ID selects the passkey, signer, and smart-account namespace. The RP origin proves which exact webpage performed this particular ceremony.

The SDK sends only the configured RP ID. The browser supplies the exact request origin and signs the ceremony origin. The server selects the registered app by clientId, requires the RP ID to match its saved configuration, and requires exact membership in the server-owned rpOrigins allowlist.

Configure the registered application in the developer dashboard before deploying the client:

{
  "rpId": "example.com",
  "rpOrigins": ["https://test1.example.com", "https://test2.example.com"]
}

Every hostname must be an exact verified non-wildcard application domain. Origins are exact: scheme and non-default port are significant. Each origin hostname must equal the RP ID or be its subdomain.

:::warning Explicit RP sharing requires both configurations Saving rpId and rpOrigins in the developer dashboard only authorizes the namespace; it does not activate it for a client. The client must also send the same value as webauthn.rpId. If the client omits webauthn.rpId, 1auth intentionally uses the page's exact hostname and does not consult the registered shared-RP configuration.

On a canonical page whose hostname equals the saved RP ID, both configurations may produce the same visible hostname. That does not prove the explicit path is active. Verify that the client sends webauthn.rpId, especially before expecting another authorized subdomain to reuse the same passkey and smart account. :::

Configure the client

oneauth.ts
import { OneAuthClient } from "@rhinestone/1auth";
 
export const oneAuth = new OneAuthClient({
  providerUrl: "https://passkey.1auth.app",
  clientId: "my-app",
  webauthn: {
    rpId: "example.com",
  },
  experimental_clear_signing: true,
  sponsorship: {
    accessTokenUrl: "/api/sponsorship/access-token",
    extensionTokenUrl: "/api/sponsorship/extension-token",
  },
});

Providing webauthn.rpId automatically selects app-origin mode. The RP ID must be the page hostname or one of its parent domains:

Page:    checkout.example.com
Allowed: checkout.example.com or example.com
Denied:  accounts.other-company.com

Your clientId must belong to the registered application serving the current page. Omit rpId to preserve the default exact-host behavior.

Before deploying this SDK configuration, open the developer dashboard, choose the verified RP ID, and add every exact page origin that may run WebAuthn. rpOrigins is server-owned configuration and is not an SDK option.

authenticate(), authenticate({ flow: "create-account" }), and authenticate({ flow: "login" }) first open the identity-only 1auth dialog. After identity verification, registration or authentication continues in your top-level page using the configured RP ID or, by default, that page's hostname.

const auth = await oneAuth.authenticate();
if (!auth.success) {
  throw new Error(auth.error?.message ?? "Authentication failed");
}
 
const result = await oneAuth.sendIntent({
  accountAddress: auth.session.accountAddress,
  targetChain: 84532,
  calls,
  sponsorshipMode: "required",
  experimental_clear_signing: true,
});

Security boundary

With experimental_clear_signing: true, the passkey-origin iframe displays the authoritative server-prepared transaction review. Approval returns to the SDK, then navigator.credentials.get() runs in the application's top-level page. The server binds and verifies the exact prepared intent, challenge, browser origin, RP ID, registered app, account, and credential before submitting anything on-chain.

There is no fallback to the cross-origin RP: fallback would select a different credential, signer, and smart account. The cross-origin compatibility surface is experimental; opt in explicitly with webauthn: { mode: 'experimental_cross_origin' } only for legacy features that do not yet support app-origin.

Supported surface

  • Fresh email or OAuth account creation
  • Login with an app-origin credential
  • getSession(), disconnect(), and authenticated setupRecovery() status
  • signMessage(), signTypedData(), and signWithModal()
  • One sendIntent() call with visible review or app-owned blind review, directly, through PayButton, through EIP-1193 eth_sendTransaction / wallet_sendCalls, or through wallet-client sendTransaction() / sendCalls()
  • Multiple calls submitted atomically as one intent
  • Origin/RP-bound passkey listing, addition, removal, recovery, and matching-intent finalization
  • SmartSession permission grants and bearer-bound headless execution through OneAuthHeadlessClient

Any API that does not support app-origin fails explicitly with APP_ORIGIN_FLOW_UNSUPPORTED; it does not silently switch to the cross-origin credential namespace.

Deployment requirements

  • Serve every calling hostname over HTTPS. http://localhost is accepted only for development and is not provider evidence.
  • The exact browser origin is always verified. Ports stay in the RP origin but never appear in the RP ID or account namespace.
  • Without webauthn.rpId, every distinct hostname creates distinct passkeys and smart accounts.
  • With webauthn.rpId, the value must be the exact caller hostname or one of its parent domains. Supplying it automatically selects app-origin mode.
  • Adding or changing webauthn.rpId changes the SDK bearer storage key, so existing browser sessions must authenticate again.
  • The registered application's RP ID and every rpOrigins hostname must be exact verified, non-wildcard application domains.
  • Wildcard origins and unrelated-site Related Origin Requests are unsupported. 1auth does not fetch /.well-known/webauthn for this configuration.
  • Configure sponsorship endpoints before sending an intent. clientId identifies application metadata and authorization; it does not override browser-origin verification.
  • Changing an RP ID or WebAuthn mode selects a different passkey keypair, on-chain signer, and smart account. 1auth does not migrate accounts between namespaces, so treat the change as a user-facing account switch, not a configuration-only rollout.
  • Validate the deployed flow on a real domain with the password managers and browsers you support.