Integrating Passkeys into your application

To securely handle passkey authentication in your application, embed the hosted Passkey UI in an iframe (web) or open it in a browser session (mobile). Below are best practices and code examples for both environments.

For more details, see the Create or Authenticate Passkey endpoint documentation.

Web Integration (React/Next.js)

1

Initiate Passkey Session

Request a passkey session from your backend, specifying the action (create or auth), and receive a hosted UI URL.

appName determines how the passkey will be named when it is created on your user’s device. Use your application’s name or a clear identifier so users can easily recognize it.

const requestPasskeySession = async (action: "create" | "auth") => {
  const appName = "YourAppName";

  // Generate a session key
  const keypair = Keypair.generate();
  const sessionKey = {
    key: keypair.publicKey.toBase58(),
    expiration: 900, // 15 minutes
  };

  const redirectUrl = encodeURIComponent(window.location.origin + "/");

  const passkeyData = {
    action: action,
    sessionKey,
    env: "devnet", // or 'mainnet'
    metaInfo: {
      appName: appName,
      redirectUrl: redirectUrl,
    },
  };

  // Get the passkey URL from your API
  const response = await fetch(
    `https://developer-api.squads.so/api/v1/passkeys`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Network": "devnet", // or 'mainnet'
        "Authorization": "Bearer YOUR_API_KEY",
      },
      body: JSON.stringify({
        action: action,
        sessionKey,
        metaInfo: {
          appName: appName,
          redirectUrl: redirectUrl,
        },
      }),
    }
  );

  const data = await response.json();
  setPasskeyUrl(data.url);
  setShowIframe(true);
};
2

Embed Hosted UI

Add the hosted Passkey UI to your app using an iframe with the correct WebAuthn permissions.

<iframe
  allow="publickey-credentials-get *; publickey-credentials-create *"
  src={passkeyUrl}
  style={{ display: "none" }}
  onError={(e) => {
    console.error("Iframe error:", e);
  }}
  onLoad={() => {
    console.log("Iframe loaded successfully");
  }}
/>
3

Handle Authentication Result

Listen for messages from the iframe to receive the session token or handle errors, then use the session token as a signer in Smart Account operations.

On successful authentication, the iframe will post a message of type authz_complete containing a sessionToken and the onchain passkey address. On error, a message of type authz_error will be sent with an error description. You can also extract these values from the redirect URL if using a full-page redirect.

useEffect(() => {
  const handleMessage = (event: MessageEvent) => {
    if (event.data.type === "authz_complete") {
      // event.data.sessionToken: Use this as a signer for Smart Account operations
      // event.data.passkeyAddress: The onchain address of the created or authenticated passkey
      console.log("Authorization complete:", event.data);
      const sessionToken = event.data.sessionToken;
      const passkeyAddress = event.data.passkeyAddress;
      // Handle successful authentication
    } else if (event.data.type === "authz_error") {
      // event.data.error: Error description
      console.log("Authorization error:", event.data.error);
      // Handle authentication error
    }
  };

  window.addEventListener("message", handleMessage);
  return () => window.removeEventListener("message", handleMessage);
}, []);

React Native Integration

1

Initiate Passkey Session

Request a passkey session from your backend and receive the hosted UI URL.

import { Linking } from 'react-native';

const appName = "YourAppName";
const action = "create"; // or "auth"
const apiKey = "YOUR_API_KEY";
const network = "devnet"; // or 'mainnet'
const redirectUri = Linking.createURL("login");

// Generate a session key
const keypair = Keypair.generate();
const sessionKey = {
  key: keypair.publicKey.toBase58(),
  expiration: 900, // 15 minutes
};

const passkeyData = {
  action,
  sessionKey,
  metaInfo: {
    appName,
    redirectUrl: redirectUri,
  },
};

// Get the passkey URL
const response = await fetch("https://developer-api.squads.so/api/v1/passkeys", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${apiKey}`,
    "x-squads-network": network,
  },
  body: JSON.stringify(passkeyData),
});

const data = await response.json();
2

Open Hosted UI in Browser

Launch the Passkey UI in the device browser using WebBrowser.openAuthSessionAsync.

const result = await WebBrowser.openAuthSessionAsync(data.url, redirectUri);
3

Process Redirect Result

Handle the redirect and extract the session token from the result for use as a signer in Smart Account operations.

// result is encoded in url
const parsed = LinkingExpo.parse(result.url);
const status = parsed.queryParams?.status;

if (status === "success") {
  // parseUrl for externally signed account
} else {
  // handle error
}

For more details, see the Create or Authenticate Passkey endpoint documentation.