Set Up Passkey Authentication - SuperTokens Docs
Set Up Passkey Authentication
Integrate standalone WebAuthn passkey authentication with the frontend and backend SDKs, Session recipe, and authentication routes.
Add passkey authentication to an existing application.
Add SuperTokens passkey authentication to this application. Inspect the existing stack and authentication setup, confirm that the backend SDK supports WebAuthn, and determine the deployment origin and relying-party configuration. Configure the frontend and backend WebAuthn and Session recipes, auth routes, HTTPS requirements, and fallback authentication where appropriate. Preserve existing conventions, do not commit secrets, and validate registration, authentication, cancellation, and unsupported-browser behavior.
Overview
This page shows you how to add the Passkeys authentication method to your project. The tutorial creates a login flow, rendered by either the Prebuilt UI components or by your own Custom UI.
Before you start
Passkeys may be unavailable because of browser, device, or authenticator support. Keep another authentication method or an account-recovery path available. A user can also cancel the browser or platform prompt; treat cancellation as an interrupted attempt, let the user retry, and do not report it as a successful sign-in or sign-up.
WebAuthn is available only in a secure context, so serve the frontend over HTTPS in production. Browsers also allow http://localhost for local development.
The relying party (RP) ID must equal the frontend hostname or be a registrable suffix of it. The expected origin must exactly match the frontend origin, including its scheme and non-default port. If the frontend and API use different hostnames, configure these values explicitly instead of relying on values derived from the.
Steps
1. Initialize the frontend SDK
UI type
Pre-built UI Drop-in components that handle the flows for you.
Custom UI Build your own UI and call the SDK directly.
React
1.1 Add the WebAuthn recipe in your main configuration file.**
import React from "react";
import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import WebAuthn from "supertokens-auth-react/recipe/webauthn";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
websiteDomain: "...",
appName: "...",
},
recipeList: [WebAuthn.init(), Session.init()],
});
1.2 Include the pre-built UI components in your application.
In order for the pre-built UI to render inside your application, you have to specify which routes show the authentication components.
The React SDK uses React Router under the hood to achieve this. Based on whether you already use this package or not in your project, there are two different ways of configuring the routes.
With React Router
import React from "react";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import { WebauthnPreBuiltUI } from "supertokens-auth-react/recipe/webauthn/prebuiltui";
import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui";
import * as reactRouterDom from "react-router-dom";
class App extends React.Component {
render() {
return (
<SuperTokensWrapper>
<BrowserRouter>
<Routes>
{/*This renders the login UI on the /auth route*/}
{getSuperTokensRoutesForReactRouterDom(reactRouterDom, [WebauthnPreBuiltUI])}
{/*Your app routes*/}
</Routes>
</BrowserRouter>
</SuperTokensWrapper>
);
}
}
Without React Router
import React from "react";
import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import { WebauthnPreBuiltUI } from "supertokens-auth-react/recipe/webauthn/prebuiltui";
import { canHandleRoute, getRoutingComponent } from "supertokens-auth-react/ui";
class App extends React.Component {
render() {
if (canHandleRoute([WebauthnPreBuiltUI])) {
// This renders the login UI on the /auth route
return getRoutingComponent([WebauthnPreBuiltUI]);
}
return <SuperTokensWrapper>{/*Your app*/}</SuperTokensWrapper>;
}
}
1.3 Call the SDK init function at the start of your application.
The invocation includes the main configuration details, as well as the recipes that you use in your setup.
Web
import SuperTokens from "supertokens-web-js";
import Session from "supertokens-web-js/recipe/session";
import WebAuthn from "supertokens-web-js/recipe/webauthn";
SuperTokens.init({
appInfo: {
apiDomain: "...",
apiBasePath: "...",
appName: "...",
},
recipeList: [Session.init(), WebAuthn.init()],
});
2. Add the passkeys UI
2.1 Add the sign up form
Create a form in which the user can input their email address. When the user submits the form, call the registerCredentialWithSignUp method like in the next code snippet.
Under the hood, the method communicates with the backend SDK to fetch the registration options. Once the backend responds, it uses the browser’s APIs to begin the registration process. For a more detailed overview of the sign-up flow check the Important Concepts page.
Web
import { registerCredentialWithSignUp } from "supertokens-web-js/recipe/webauthn";
async function signUp(email: string) {
try {
let response = await registerCredentialWithSignUp({
email,
userContext: {},
});
if (response.status === "SIGN_UP_NOT_ALLOWED" || response.status === "INVALID_AUTHENTICATOR_ERROR") {
window.alert(response.reason);
} else if (response.status === "INVALID_EMAIL_ERROR" || response.status === "EMAIL_ALREADY_EXISTS_ERROR") {
window.alert("Invalid email");
} else if (
response.status === "INVALID_CREDENTIALS_ERROR" ||
response.status === "OPTIONS_NOT_FOUND_ERROR" ||
response.status === "INVALID_OPTIONS_ERROR" ||
response.status === "AUTHENTICATOR_ALREADY_REGISTERED" ||
response.status === "FAILED_TO_REGISTER_USER" ||
response.status === "WEBAUTHN_NOT_SUPPORTED"
) {
window.alert("Please try again");
} else if (response.status === "INVALID_GENERATED_OPTIONS_ERROR") {
window.alert("The registration request expired. Please try again.");
} else if (response.status === "GENERAL_ERROR") {
window.alert(response.message);
} else if (response.status === "OK") {
window.alert("You have been signed up successfully");
} else {
window.alert("Sign up could not be completed. Please try another authentication method.");
}
} catch (err: any) {
if (err.isSuperTokensGeneralError === true) {
window.alert(err.message);
} else {
window.alert("Oops! Something went wrong.");
}
}
}
2.2 Add the login form
Add a button that can trigger the sign in flow. This is all that you need in terms of UI. When the user clicks it, call the authenticateCredentialWithSignIn method to handle the whole process.
Web
import { authenticateCredentialWithSignIn } from "supertokens-web-js/recipe/webauthn";
async function signIn() {
try {
let response = await authenticateCredentialWithSignIn({ userContext: {} });
if (response.status === "SIGN_IN_NOT_ALLOWED") {
window.alert(response.reason);
} else if (response.status === "WEBAUTHN_NOT_SUPPORTED") {
window.alert("Login method not supported");
} else if (
response.status === "INVALID_CREDENTIALS_ERROR" ||
response.status === "INVALID_OPTIONS_ERROR" ||
response.status === "FAILED_TO_AUTHENTICATE_USER"
) {
window.alert("Please try again");
} else if (response.status === "GENERAL_ERROR") {
window.alert(response.message);
} else if (response.status === "OK") {
window.alert("You have been signed in successfully");
} else {
window.alert("Sign in could not be completed. Please try another authentication method.");
}
} catch (err: any) {
if (err.isSuperTokensGeneralError === true) {
window.alert(err.message);
} else {
window.alert("Oops! Something went wrong.");
}
}
}
3. Initialize the backend SDK
Initialize the backend SDK and include the WebAuthn recipe. The init call includes configuration details for your app. It specifies how the backend connects to the SuperTokens Core, as well as the Recipes used in your setup.