/
Contact usSee pricingStart building
Node
​

    About Stytch

    Introduction
    Integration Approaches
      Full-stack overview
      Frontend (pre-built UI)
      Frontend (headless)
      Backend
    Migrations
      Migration overview
      Migrating users statically
      Migrating users dynamically
      Additional migration considerations
      Zero-downtime deployment
      Defining external IDs for users
      Exporting from Stytch
    Custom Domains
      Overview

    Authentication

    DFP Protected Auth
      Overview
      Setting up DFP Protected Auth
      Handling challenges
    Magic Links
    • Email Magic Links

      • Getting started with the API
        Getting started with the SDK
        Replacing your password reset flow
        Building an invite user flow
        Add magic links to an existing auth flow
        Adding PKCE to a Magic Link flow
        Magic Link redirect routing
    • Embeddable Magic Links

      • Getting started with the API
    MFA
      Overview
      Backend integration
      Frontend integration
    Mobile Biometrics
      Overview
    M2M Authentication
      Authenticate an M2M Client
      Rotate client secrets
      Import M2M Clients from Auth0
    OAuth
    • Identity providers

      • Overview
        Provider setup
      Getting started with the API (Google)
      Add Google One Tap via the SDK
      Email address behavior
      Adding PKCE to an OAuth flow
    Connected AppsBeta
      Setting up Connected Apps
      About Remote MCP Servers
    • Resources

      • Integrate with AI agents
        Integrate with MCP servers
        Integrate with CLI Apps
    Passcodes
      Getting started with the API
      Getting started with the SDK
    • Toll fraud

      • What is SMS toll fraud?
        How you can prevent toll fraud
      Unsupported countries
    Passkeys & WebAuthn
    • Passkeys

      • Passkeys overview
        Set up Passkeys with the frontend SDK
    • WebAuthn

      • Getting started with the API
        Getting started with the SDK
    Passwords
      Getting started with the API
      Getting started with the SDK
      Password strength policy
    • Email verification

      • Overview
        Email verification before password creation
        Email verification after password creation
    Sessions
      How to use sessions
      Backend integrations
      Frontend integrations
      Custom claims
      Custom claim templates
      Session tokens vs JWTs
      How to use Stytch JWTs
    TOTP
      Getting started with the API
      Getting started with the SDK
    Web3
      Getting started with the API
      Getting started with the SDK

    Authorization

    Implement RBAC with metadata

    3rd Party Integrations

    Planetscale
    Supabase
    Feathery
    Unit

    Testing

    E2E testing
    Sandbox values
Get support on SlackVisit our developer forum

Contact us

Consumer Authentication

/

Guides

/

Authentication

/

Passkeys & WebAuthn

/

Passkeys

/

Set up Passkeys with the frontend SDK

Set up Passkeys with the frontend SDK

Passkeys are a biometrics-based, phishing-resistant, drop-in replacement for passwords. Stytch's Passkeys utilize local biometric verifications like FaceID or TouchID to generate asymmetric public-private keys for authentication.

In this guide, you'll learn how to set up Passkeys for login with Stytch's frontend SDK. By the end, you'll have:

  • Configured a Stytch Login component.
  • Configured a Passkey Registration component.
  • Signed up a User with Email OTP.
  • Registered a Passkey.
  • Authenticated a User with the Passkey.

Before you start

In order to complete this guide, you'll need the following:

  • A Stytch Consumer Authentication project. If you don't have one already, in the Dashboard, click on your existing project name in the top left corner of the Dashboard, click Create a new project, and then select Consumer Authentication.
  • The project Test environment's public token from the API keys section. You'll need to pass the public token into the initialized SDK client.
  • The SDK enabled. In the Dashboard, navigate to Frontend SDK under CONFIGURATION. Then click Enable SDK in Test.
  • WebAuthn enabled in the SDK settings under Authentication products.
  • A web app that serves html pages.

Passkeys require a primary factor

In order to ensure account recovery, Passkeys can only be used for login and not signup. Stytch Users are required to have a verified email or phone from primary auth factors like Magic Links, OTP, and OAuth before they can register a Passkey with Stytch's API.

Additionally, Passkey registration requires the User to have authenticated with at least two factors if possible. Please refer to the MFA SDK resource for more details.

Step 1: Install the frontend SDK

Stytch provides frontend SDK options for vanilla JavaScript, React, and Next.js. The essential steps to set up Passkeys are the same regardless of which SDK implementation you decide to use.

In this guide, we'll use the vanilla JavaScript SDK.

Install the frontend SDK locally via npm or yarn, or use unpkg to always pull the most current SDK version.

npm install @stytch/vanilla-js --save
<script type="module" src="https://www.unpkg.com/@stytch/vanilla-js"></script>

Step 2: Create a login.html page and initialize the Stytch Client

The next step is to create a login page with two elements:

  1. A <script> that initializes the Stytch Client. You'll need to pass in your Project's public token.
  2. A DOM element for the login UI component.
<!-- login.html -->
<script>
// step 2
import { StytchUIClient } from '@stytch/vanilla-js';
const stytch = new StytchUIClient('PUBLIC_TOKEN');
</script>

<div id="login-form"></div>

Step 3: Configure and mount the Login component

After the initializing the Stytch Client, create a config object with the necessary auth settings. Refer to the UI Config SDK reference for all available options and style customizations.

Since Passkeys cannot be used for signup, include One-Time Passcodes as an auth factor in the config object. Then mount the Login component by calling the stytch.mountLogin() method and passing in an object that has the config object and the DOM element id from Step 2.

<!-- login.html -->
<script>
// step 2
import { StytchUIClient } from '@stytch/vanilla-js';
const stytch = new StytchUIClient('PUBLIC_TOKEN');

// step 3
const config = {
  otpOptions: {
    expirationMinutes: 10,
    methods: ['email', 'sms']
  },
  products: [
    'otp',
    'passkeys'
  ],
};

stytch.mountLogin({
  elementId: "#login-form",
  config,
});
</script>

<div id="login-form"></div>

Step 4: Add callbacks to redirect to the home.html page

With the login form working, create a callbacks object that redirects the user upon successful authentication to a logged-in location (like a home page, dashboard, or account page). You can wire these functions to trigger on the PASSKEY_AUTHENTICATE and OTP_AUTHENTICATE events.

Refer to the UI callbacks SDK reference for a full list of events you can use for asycchronous operations.

Once defined, pass the callbacks object into stytch.mountLogin() method.

<!-- login.html -->
<script>
// step 2
import { StytchUIClient } from '@stytch/vanilla-js';
const stytch = new StytchUIClient('PUBLIC_TOKEN');

// step 3
const config = {
  otpOptions: {
    expirationMinutes: 10,
    methods: ['email', 'sms']
  },
  products: [
    'otp',
    'passkeys'
  ],
};

// step 4
const callbacks = {
  onEvent: ({ type, data }) => {
    if (type === 'PASSKEY_AUTHENTICATE') {
      console.log("Passkey authenticated", data);
      window.location.replace("/home");
    } else if (type === 'OTP_AUTHENTICATE') {
      console.log("OTP authenticated", data);
      window.location.replace("/home");
    } else {
      console.log(type, data)
    }
  },
  onError: (err) => {
    console.log(err);
  }
};

stytch.mountLogin({
  elementId: "#login-form",
  config,
  callbacks
});
</script>

<div id="login-form"></div>

The login.html page should render a Login component UI. The email input field should trigger an autofill behavior for Passkey credentials when clicked on. Please make sure you're using a supported browser.

Passkeys diagramPasskeys diagram

Step 5: Create a home.html page and mount the Passkey Registration component

With the login.html page redirecting to home.html upon successful authentication, the next step is to build a page where users can register Passkeys after signing up.

Create a home.html page that initializes the Stytch Client and mounts the Passkey Registration component. The Passkey Registration component accepts all the same props as the Stytch Login component from Steps 3 and 4:

  • config object.
  • target DOM element id.
  • callbacks object.

You'll need to also create a logout mechanism using the stytch.session.revoke() method.

The home.html page should have the following structure:

<!-- home.html -->
<script>
// step 5
import { StytchUIClient } from '@stytch/vanilla-js';
const stytch = new StytchUIClient('PUBLIC_TOKEN');

const logout = () => {
  stytch.session.revoke();
};

const config = {
  otpOptions: {
    expirationMinutes: 10,
    methods: ['email', 'sms']
  },
  products: [
    'otp',
    'passkeys'
  ],
};

const callbacks = {
  onEvent: ({ type, data }) => {
    if (type === 'PASSKEY_REGISTER') {
      console.log("Passkey registered", data);
      window.location.replace("/home");
    } else {
      console.log(type, data)
    }
  },
  onError: (err) => {
    console.log(err);
  }
};

stytch.mountPasskeyRegistration({
  elementId: "#stytch-passkey-form",
  config,
  callbacks
});


</script>

<div id="register-passkey-form"></div>

<button onclick="logout()">Log out</button>

The home.html page should render a Passkey Registration component with this UI:

Passkeys diagram

Step 6: Sign up with Email OTP

At this point, the login.html and home.html should have fully functional Login and Passkey Registration components. Now we can test the end-to-end flow for signing up and logging in to the application with Passkeys.

First, start on the login.html page and enter an email address to sign up with an Email OTP. You should receive an email with an OTP code. Complete the authentication flow and you should be redirected to home.html after receiving a 200 network response with a Session.

Passkeys diagram

Step 7: Register a Passkey

On the home.html page, click Create a Passkey on the Passkey Registration component. A browser dialog will appear with a prompt to create a Passkey with multiple options for storage such as:

  • Mobile devices
  • Tablets
  • Laptops
  • Security hardware like Yubikeys
  • iCloud
  • Chrome password manager
  • Windows Hello
  • 1Paswsword

The available options are determined by the end user's specific setup of devices, operating systems, and browsers. For example, someone who has a Macbook laptop with Chrome browser and 1Password installed may see the following dialogs appear for registering Passkeys:

Passkeys diagramPasskeys diagram

Select any option and follow all prompted steps to create a Passkey. The end result should be a 200 network response with a Session and the Passkey Registration component displaying a success message:

Passkeys diagram

Step 8: Authenticate with your Passkey

Your User record should have a verified email from signing up with OTP in Step 6 and a registered Passkey / WebAuthn factor from Step 7.

{
  "user_id": "user-test-c872...",
  "status": "active",
  "created_at": "2023-11-21T17:05:05Z",
  "emails": [
    {
      "email": "example@email.com",
      "email_id": "email-test-8c...",
      "verified": true
    }
  ],
  "webauthn_registrations": [
    {
      "authenticator_type": "",
      "domain": "localhost",
      "name": "WebAuthN Registration 531ca878",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
      "verified": true,
      "webauthn_registration_id": "webauthn-registration-test-a71f6..."
    }
  ],
  "email": "example@email.com",
  "phone_number": "",
  "name": {
    "first_name": "",
    "last_name": "",
    "middle_name": ""
  },
  "password": null,
  "phone_numbers": [],
  "providers": [],
  "totps": [],
  "trusted_metadata": {},
  "untrusted_metadata": {}
}

Log out of the home.html page and revoke the session with the logout() function created in Step 5.

The final step is to log back in by clicking the email input field which should trigger the autofill and Passkeys browser dialog.

Select the same Passkey you created in Step 7 which will succesfully authenticate into the application.

What's next

Clone the React or Next.js example app to get hands-on with a Passkeys-powered application.

Before you start

Passkeys require a primary factor

Step 1: Install the frontend SDK

Step 2: Create a login.html page and initialize the Stytch Client

Step 3: Configure and mount the Login component

Step 4: Add callbacks to redirect to the home.html page

Step 5: Create a home.html page and mount the Passkey Registration component

Step 6: Sign up with Email OTP

Step 7: Register a Passkey

Step 8: Authenticate with your Passkey

What's next