From af7ad0db54320aba7a2440be5e075088b5f1df68 Mon Sep 17 00:00:00 2001 From: Bogdan Carpusor Date: Wed, 8 Jan 2025 15:52:40 +0200 Subject: [PATCH] Add the initial webauthn docs --- .../authentication/webauthn/_category_.json | 4 + .../authentication/webauthn/_structure.mdx | 44 ++++ .../customise-credential-validation.mdx | 185 ++++++++++++++ .../authentication/webauthn/initial-setup.mdx | 226 ++++++++++++++++++ .../authentication/webauthn/introduction.mdx | 118 +++++++++ 5 files changed, 577 insertions(+) create mode 100644 v3/docs/authentication/webauthn/_category_.json create mode 100644 v3/docs/authentication/webauthn/_structure.mdx create mode 100644 v3/docs/authentication/webauthn/customise-credential-validation.mdx create mode 100644 v3/docs/authentication/webauthn/initial-setup.mdx create mode 100644 v3/docs/authentication/webauthn/introduction.mdx diff --git a/v3/docs/authentication/webauthn/_category_.json b/v3/docs/authentication/webauthn/_category_.json new file mode 100644 index 000000000..cf58b5fa3 --- /dev/null +++ b/v3/docs/authentication/webauthn/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Passkey Authentication", + "position": 7 +} diff --git a/v3/docs/authentication/webauthn/_structure.mdx b/v3/docs/authentication/webauthn/_structure.mdx new file mode 100644 index 000000000..e13f59d81 --- /dev/null +++ b/v3/docs/authentication/webauthn/_structure.mdx @@ -0,0 +1,44 @@ +--- +title: Structure +hide_title: true +sidebar_position: 1 +--- + +# Introduction +## Overview +## Why to use WebAuthn +## What are Passkeys? +## Terminology +## Feature Overview +## Integration Options +## Getting Started + +# Quick Start +## Overview +## Before you start +### Terminology +## Steps (Custom UI) +### Initialize the Frontend SDK +### Add the UI +### Add the Signup Form +### Add the Login Form +### Initialize the Backend SDK +## Steps (Prebuilt UI) +### Initialize the Frontend SDK +### Initialize the Backend SDK +## Next Steps + + +# Account Recovery +## Overview + +# Customise Passkey Validation +## Overview +## Available options + +# Configuring the Relying Party and Multitenancy +## Overview +## Configuring the Relying Party + + + diff --git a/v3/docs/authentication/webauthn/customise-credential-validation.mdx b/v3/docs/authentication/webauthn/customise-credential-validation.mdx new file mode 100644 index 000000000..b17dc0e43 --- /dev/null +++ b/v3/docs/authentication/webauthn/customise-credential-validation.mdx @@ -0,0 +1,185 @@ +--- +title: Customise Credential Validation +hide_title: true +sidebar_position: 3 +--- + +# Customise Credential Validation + +## Overview + +The WebAuthN flow allows the user to customise the way credentials are generated and validated. The reason for this is that certain use-cases require the user to have a lot of control over the credential generation and validation process. + +For example, in the case of a banking app, the user may want to use a YubiKey to generate and validate credentials. In this case, the user may want to use a required PIN or a biometric factor to validate the credential. + +TODO: Add correct link +Most of the customisation is done through function overrides. You can find more details about how they work here: [Overrides](https://deploy-preview-869--starlit-elf-06ee1a.netlify.app/docs/references/sdks/functions-overrides/backend-functions-override). + +## Recipe Configuration + +TODO: Add correct link +The recipe configuration is done by the `init` function. You can find more details about the recipe configuration here: [Recipe Configuration](#). + +When configuring the recipe, you can pass the following options: +- **Relying Party**: Details about the entity for which the credential is being generated. This includes the domain name (Relying Party ID) and display name (Relying Party Name) of your application that will be shown to the user during authentication. The Relying Party ID defaults to the API domain (`apiBasePath`) and the Relying Parth Name defaults to the application name (`appName`). +- **Origin**: The origin URL that the credential is generated on. Defaults to the origin of the request. + +```ts +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import WebAuthn from "supertokens-node/recipe/webauthn"; + +supertokens.init({ + framework: "express", + supertokens: { + // https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core. + connectionURI: "https://try.supertokens.com", + // apiKey: , + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" + }, + recipeList: [ + WebAuthn.init({ + getOrigin: () => { + return "https://example.com"; + }, + getRelyingPartyId: () => { + return "example.com"; + }, + getRelyingPartyName: () => { + return "example"; + }, + }), + Session.init() // initializes session features + ] +}); +``` + +## Customising Credential Generation + +The credentials are generated by the client (if it supports it). You can find more details about the way the browser handles credential generation here: [Credential Management API](https://developer.mozilla.org/en-US/docs/Web/API/Credential_Management_API). + +The credential is generated based on a set of options that you can pass to the `navigator.credentials.create` function. In our case these options are generated on the server through the SDK. + +The possible configurable options are: + +- **Relying Party**: Details about the entity for which the credential is being generated. This includes the domain name (Relying Party ID) and display name (Relying Party Name) of your application that will be shown to the user during authentication. The Relying Party ID defaults to the API domain (`apiBasePath`) and the Relying Parth Name defaults to the application name (`appName`). +- **Origin**: The origin URL that the credential is generated on. Defaults to the origin of the request. +- **Timeout**: The time in milliseconds that the user has to complete the credential generation process. Defaults to `6000`. +- **Attestation**: Controls how much information about the authenticator is included in the attestation statement. This controls what authenticators are supported. Defaults to `none`. +- **Supported Algorithms**: The cryptographic algorithms that can be used for generating credentials. Different authenticators support different algorithms. Defaults to `[-8, -7, -257]`. +- **Resident Key**: Whether the credential should be stored on the authenticator device. Defaults to `required`. +- **User Verification**: Controls whether user verification (like PIN or biometrics) is required. Defaults to `preferred`. +- **User Display Name**: The display name of the user. Defaults to the `email` field. + +Below is an example of how you can customise the credential generation options. + +```ts +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import WebAuthn from "supertokens-node/recipe/webauthn"; + +supertokens.init({ + framework: "express", + supertokens: { + // https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core. + connectionURI: "https://try.supertokens.com", + // apiKey: , + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" + }, + recipeList: [ + WebAuthn.init({ + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + registerOptions: (input) => { + return originalImplementation.registerOptions({ + ...input, + attestation: "direct", + residentKey: "required", + timeout: 10 * 1000, + userVerification: "required", + displayName: "John Doe", + supportedAlgorithms: [-257], + relyingPartyId: 'example.com', + relyingPartyName: 'example', + origin: 'https://example.com', + }); + }, + }; + }, + }, + }), + Session.init() // initializes session features + ] +}); +``` + +## Customising Credential Validation + +When a user attempts to login using a WebAuthN credential, the credential is used for signing a challenge through the client using `navigator.credentials.get` function. The options for signing the challenge are generated on the server through the SDK and defined how the authentication will take place: + +- **Relying Party ID**: The domain name (Relying Party ID) of your application that will be used for validating the credential. +- **Origin**: The origin URL that the credential is generated on. Defaults to the origin of the request. +- **Timeout**: The time in milliseconds that the user has to complete the credential validation process. Defaults to `6000`. +- **User Verification**: Controls whether user verification (like PIN or biometrics) is required. Defaults to `preferred`. + +Below is an example of how you can customise the credential generation options. + +```ts +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import WebAuthn from "supertokens-node/recipe/webauthn"; + +supertokens.init({ + framework: "express", + supertokens: { + // https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core. + connectionURI: "https://try.supertokens.com", + // apiKey: , + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/session/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth" + }, + recipeList: [ + WebAuthn.init({ + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + signInOptions: (input) => { + return originalImplementation.signInOptions({ + ...input, + timeout: 10 * 1000, + userVerification: "required", + relyingPartyId: 'example.com', + origin: 'https://example.com', + }); + }, + }; + }, + }, + }), + Session.init() // initializes session features + ] +}); +``` diff --git a/v3/docs/authentication/webauthn/initial-setup.mdx b/v3/docs/authentication/webauthn/initial-setup.mdx new file mode 100644 index 000000000..ccad15561 --- /dev/null +++ b/v3/docs/authentication/webauthn/initial-setup.mdx @@ -0,0 +1,226 @@ +--- +title: Initial Setup +hide_title: true +sidebar_position: 2 +--- + +import { UIType } from "/src/components/UITypeSwitch"; + +# Quickstart + +## Overview + +This page will show you how to add the WebAuthn recipe to your project. The tutorial creates a login flow, rendered by either our Prebuilt UI components or by your own Custom UI. + +## Before you start + +-- important note -- +These intructions assume that you already have gone through our main quickstart guide. If you have skipped that page please follow the tutorial and return here once you're done. + + +## Steps + + + + + +prebuilt + + + + + +### 1. Initialize the Frontend SDK + + +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 will be using in your setup. + +- Web +```ts +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 Authentication UI + +The following section will demonstrate you what aspects you need to cover in order to implement the UI for the WebAuthN flow. + + +#### 2.1 Add the Signup Form + +You will have to first add the UI elements which will render your form. When the users submits the form you will have to call the following API to create the credential and send it to the backend in order to create the user and store the credential. + +```ts +import { registerAndSignup } from "supertokens-web-js/recipe/webauthn"; + +async function signUp(email: string) { + try { + let response = await registerAndSignUp({ + email + }); + + if ( + response.status === "SIGN_UP_NOT_ALLOWED" || + response.status === "INVALID_AUTHENTICATOR_ERROR" + ) { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else if (response.status === "INVALID_EMAIL_ERROR") { + window.alert("Please enter a valid email address"); + } else if (response.status === "EMAIL_ALREADY_EXISTS_ERROR") { + window.alert("Please enter a different email address"); + } else if ( + response.status === "AUTHENTICATOR_ALREADY_REGISTERED" || + response.status === "INVALID_GENERATED_OPTIONS_ERROR" || + response.status === "INVALID_CREDENTIALS_ERROR" || + response.status === "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR" || + response.status === "GENERATED_OPTIONS_NOT_FOUND_ERROR" + ) { + // These errors represent various issues with the authenticator, credential or the flow itself. + // These should be handled individually by you. + // The user should be informed that they should retry the sign up process or get in touch with you. + window.alert("Please try again"); + } else { + // User signed up successfully. + window.alert("You have been signed up successfully"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + // or if the input email / phone number is not valid. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + +#### 2.2 Add the Login Form + +You will have to first add the UI elements which will render your form. When the users submits the form you will have to call the following API to use the credential and send the response to the backend in order to login the user. + +```ts +import { authenticateAndSignIn } from "supertokens-web-js/recipe/webauthn"; + +async function signIn(email: string) { + try { + let response = await authenticateAndSignIn({ + email + }); + + if ( + response.status === "SIGN_IN_NOT_ALLOWED" + ) { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + window.alert(response.reason) + } else if (response.status === "INVALID_CREDENTIALS_ERROR") { + window.alert("Please enter a valid email address or use the correct passkey"); + } else if ( + response.status === "INVALID_GENERATED_OPTIONS_ERROR" + ) { + // These errors represent various issues with the authenticator, credential or the flow itself. + // These should be handled individually by you. + // The user should be informed that they should retry the sign in process or get in touch with you. + window.alert("Please try again"); + } else { + // User signed in successfully. + window.alert("You have been signed in successfully"); + } + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + // or if the input email / phone number is not valid. + window.alert(err.message); + } else { + window.alert("Oops! Something went wrong."); + } + } +} +``` + +### 3. Initialize the Backend SDK + +You will have to intialize the Backend SDK alongside the code that starts your server. The init call will include configuration details for your app, how the backend will connect to the SuperTokens Core, as well as the Recipes that will be used in your setup. + +For the WebAuthN recipe, you can also specify the following optional parameters: +- `emailDelivery`: Configure how verification emails are sent to users. You can use the default email service or integrate your own email delivery provider. + +- `getRelyingPartyId`: Set the domain name that will be associated with the WebAuthn credentials (e.g. "example.com"). This helps ensure credentials can only be used on your domain. It defaults to the origin domain. + +- `getRelyingPartyName`: Set a human-readable name for your application that will be shown to users during the WebAuthn registration process (e.g. "My App"). It defaults to the app name. + +- `validateEmailAddress`: Add custom validation logic for email addresses. By default, basic email format validation is performed. + +- `getOrigin`: Configure the origin URL that WebAuthn credentials will be bound to (e.g. "https://example.com"). This should match your application's domain and protocol. + + +```ts +import supertokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import WebAuthN from "supertokens-node/recipe/webauthn"; + +supertokens.init({ + // Replace this with the framework you are using + framework: "express", + supertokens: { + // We use try.supertokens for demo purposes. + // At the end of the tutorial we will show you how to create + // your own SuperTokens core instance and then update your config. + connectionURI: "https://try.supertokens.io", + // apiKey: + }, + appInfo: { + // learn more about this on https://supertokens.com/docs/emailpassword/appinfo + appName: "", + apiDomain: "", + websiteDomain: "", + apiBasePath: "/auth", + websiteBasePath: "/auth", + }, + recipeList: [ + WebAuthN.init({ + getRelyingPartyId: () => { + return ''; + }, + getRelyingPartyName: () => { + return ''; + }, + }), + Session.init() + ] +}); +``` + + + + +## Next Steps + +Now that you have completed the main setup you can explore more advanced topics related to the WebAuthN recipe. + + + + + + + + + diff --git a/v3/docs/authentication/webauthn/introduction.mdx b/v3/docs/authentication/webauthn/introduction.mdx new file mode 100644 index 000000000..bfae8f220 --- /dev/null +++ b/v3/docs/authentication/webauthn/introduction.mdx @@ -0,0 +1,118 @@ +--- +title: Introduction +hide_title: true +sidebar_position: 1 +--- + +# Introduction + +## Overview + +WebAuthn (Web Authentication) is a modern authentication standard that enables passwordless authentication using biometric sensors (like fingerprint readers or facial recognition) or security keys (like YubiKeys). This feature allows your users to authenticate without passwords, providing both enhanced security and improved user experience. + +(-- add image with login page here --) + +## Why to use WebAuthn + +- Provides superior security compared to traditional passwords by using cryptographic authentication +- Offers a seamless user experience with biometric authentication (fingerprint, face recognition) +- Eliminates phishing attacks since credentials are bound to the origin +- Reduces account takeover risks and password-related vulnerabilities +- Helps meet regulatory compliance requirements for strong authentication +- Lowers support costs by eliminating password resets + +## What are Passkeys? + +Passkeys are a user-friendly implementation of WebAuthn credentials that make passwordless authentication more accessible. They represent the next evolution in authentication, backed by major platform providers like Apple, Google, and Microsoft. + +Key aspects of passkeys include: + +- **Syncing Across Devices**: Unlike traditional WebAuthn credentials that are device-specific, passkeys can sync across a user's devices through their platform account (iCloud, Google account, etc.) + +- **Platform Integration**: Passkeys are deeply integrated into operating systems and browsers, providing a seamless experience across different platforms and devices + +- **Enhanced Security**: + - End-to-end encryption during syncing + - Phishing-resistant by design + - Based on public key cryptography + - Protected by biometric authentication or device PIN + +- **Improved User Experience**: + - No passwords to remember + - Automatic syncing between devices + - Quick and easy authentication using biometrics + - Familiar system UI for authentication + +While passkeys and WebAuthn credentials share the same underlying technology, passkeys add the convenience of cross-device availability while maintaining the strong security guarantees of WebAuthn. + +## Terminology + +Before diving into WebAuthn implementation, it's important to understand the key terminology used throughout this documentation. WebAuthn introduces several new technical concepts and terms that may be unfamiliar to developers. This section will help you better understand the documentation and the WebAuthn specification. + +For a more detailed explanation of the WebAuthn specification, you can refer to the [WebAuthn specification](https://www.w3.org/TR/webauthn/). + +Note: Throughout our documentation, the terms "passkey" and "credential" are used interchangeably, though they have subtle technical differences explained below. + +- **Passkey**: A user-friendly term for WebAuthn credentials that are synced across a user's devices. Passkeys are: + - More convenient than traditional credentials as they sync automatically + - Backed by platform providers like Apple, Google, and Microsoft + - Protected by end-to-end encryption during syncing + +- **Credential**: The technical term for the cryptographic key pairs used in WebAuthn. Unlike passkeys: + - Credentials are device-specific and not synced + - They represent the raw cryptographic material + - Multiple credentials can be part of a single passkey + +- **Authenticator**: A device or software that implements WebAuthn authentication. This can be: + - **Platform Authenticator**: Built-in biometric sensors like TouchID, FaceID, or Windows Hello + - **Roaming Authenticator**: External security devices like YubiKeys or Google Titan keys + +- **Registration**: The process where a user registers their authenticator with your application. During this process: + - The server generates a challenge for the authenticator to sign + - The authenticator creates a new credential + - The public key and other metadata are saved to your database + +- **Authentication**: The process where a user proves their identity using their authenticator by: + - Responding to a server challenge + - Using their private key to sign the challenge + - The server verifying the signature with the stored public key + +- **Attestation**: Information about the authenticator device itself, which can be used to verify the authenticator's authenticity and security level. + +- **User Verification**: The method used to verify the user's presence, which can be: + - Biometric verification (fingerprint, face scan) + - PIN entry + - Physical button press on a security key + + +## Feature Overview + +The WebAuthn feature in SuperTokens provides: + +- Complete implementation of the WebAuthn standard +- Support for platform authenticators (biometric sensors) and roaming authenticators (security keys) +- Automatic handling of device registration and authentication +- Integration with other SuperTokens features +- Cross-platform compatibility + +## Integration Options + +You can implement WebAuthn in your application in several ways: + +1. **Standalone WebAuthn**: Use WebAuthn as the primary authentication method +2. **Multi-factor Authentication**: Add WebAuthn as a second factor alongside passwords +3. **Hybrid Setup**: Combine WebAuthn with other authentication methods like passwordless/magic links + +## Prerequisites + +Before implementing WebAuthn, ensure: + +- Your application runs on HTTPS (required for WebAuthn) +- Your users have compatible devices with either: + - Built-in biometric sensors (TouchID, FaceID, Windows Hello) + - External security keys (YubiKey, Google Titan) +- Your backend can handle the WebAuthn protocol + +## Getting Started + +For detailed implementation instructions, check out our [Quick Setup](/docs/authentication/webauthn/initial-setup) guide.