|
| 1 | +--- |
| 2 | +title: Customise Credential Validation |
| 3 | +hide_title: true |
| 4 | +sidebar_position: 3 |
| 5 | +--- |
| 6 | + |
| 7 | +# Customise Credential Validation |
| 8 | + |
| 9 | +## Overview |
| 10 | + |
| 11 | +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. |
| 12 | + |
| 13 | +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. |
| 14 | + |
| 15 | +TODO: Add correct link |
| 16 | +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). |
| 17 | + |
| 18 | +## Recipe Configuration |
| 19 | + |
| 20 | +TODO: Add correct link |
| 21 | +The recipe configuration is done by the `init` function. You can find more details about the recipe configuration here: [Recipe Configuration](#). |
| 22 | + |
| 23 | +When configuring the recipe, you can pass the following options: |
| 24 | +- **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`). |
| 25 | +- **Origin**: The origin URL that the credential is generated on. Defaults to the origin of the request. |
| 26 | + |
| 27 | +```ts |
| 28 | +import supertokens from "supertokens-node"; |
| 29 | +import Session from "supertokens-node/recipe/session"; |
| 30 | +import WebAuthn from "supertokens-node/recipe/webauthn"; |
| 31 | + |
| 32 | +supertokens.init({ |
| 33 | + framework: "express", |
| 34 | + supertokens: { |
| 35 | + // 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. |
| 36 | + connectionURI: "https://try.supertokens.com", |
| 37 | + // apiKey: <API_KEY(if configured)>, |
| 38 | + }, |
| 39 | + appInfo: { |
| 40 | + // learn more about this on https://supertokens.com/docs/session/appinfo |
| 41 | + appName: "<YOUR_APP_NAME>", |
| 42 | + apiDomain: "<YOUR_API_DOMAIN>", |
| 43 | + websiteDomain: "<YOUR_WEBSITE_DOMAIN>", |
| 44 | + apiBasePath: "/auth", |
| 45 | + websiteBasePath: "/auth" |
| 46 | + }, |
| 47 | + recipeList: [ |
| 48 | + WebAuthn.init({ |
| 49 | + getOrigin: () => { |
| 50 | + return "https://example.com"; |
| 51 | + }, |
| 52 | + getRelyingPartyId: () => { |
| 53 | + return "example.com"; |
| 54 | + }, |
| 55 | + getRelyingPartyName: () => { |
| 56 | + return "example"; |
| 57 | + }, |
| 58 | + }), |
| 59 | + Session.init() // initializes session features |
| 60 | + ] |
| 61 | +}); |
| 62 | +``` |
| 63 | + |
| 64 | +## Customising Credential Generation |
| 65 | + |
| 66 | +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). |
| 67 | + |
| 68 | +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. |
| 69 | + |
| 70 | +The possible configurable options are: |
| 71 | + |
| 72 | +- **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`). |
| 73 | +- **Origin**: The origin URL that the credential is generated on. Defaults to the origin of the request. |
| 74 | +- **Timeout**: The time in milliseconds that the user has to complete the credential generation process. Defaults to `6000`. |
| 75 | +- **Attestation**: Controls how much information about the authenticator is included in the attestation statement. This controls what authenticators are supported. Defaults to `none`. |
| 76 | +- **Supported Algorithms**: The cryptographic algorithms that can be used for generating credentials. Different authenticators support different algorithms. Defaults to `[-8, -7, -257]`. |
| 77 | +- **Resident Key**: Whether the credential should be stored on the authenticator device. Defaults to `required`. |
| 78 | +- **User Verification**: Controls whether user verification (like PIN or biometrics) is required. Defaults to `preferred`. |
| 79 | +- **User Display Name**: The display name of the user. Defaults to the `email` field. |
| 80 | + |
| 81 | +Below is an example of how you can customise the credential generation options. |
| 82 | + |
| 83 | +```ts |
| 84 | +import supertokens from "supertokens-node"; |
| 85 | +import Session from "supertokens-node/recipe/session"; |
| 86 | +import WebAuthn from "supertokens-node/recipe/webauthn"; |
| 87 | + |
| 88 | +supertokens.init({ |
| 89 | + framework: "express", |
| 90 | + supertokens: { |
| 91 | + // 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. |
| 92 | + connectionURI: "https://try.supertokens.com", |
| 93 | + // apiKey: <API_KEY(if configured)>, |
| 94 | + }, |
| 95 | + appInfo: { |
| 96 | + // learn more about this on https://supertokens.com/docs/session/appinfo |
| 97 | + appName: "<YOUR_APP_NAME>", |
| 98 | + apiDomain: "<YOUR_API_DOMAIN>", |
| 99 | + websiteDomain: "<YOUR_WEBSITE_DOMAIN>", |
| 100 | + apiBasePath: "/auth", |
| 101 | + websiteBasePath: "/auth" |
| 102 | + }, |
| 103 | + recipeList: [ |
| 104 | + WebAuthn.init({ |
| 105 | + override: { |
| 106 | + functions: (originalImplementation) => { |
| 107 | + return { |
| 108 | + ...originalImplementation, |
| 109 | + registerOptions: (input) => { |
| 110 | + return originalImplementation.registerOptions({ |
| 111 | + ...input, |
| 112 | + attestation: "direct", |
| 113 | + residentKey: "required", |
| 114 | + timeout: 10 * 1000, |
| 115 | + userVerification: "required", |
| 116 | + displayName: "John Doe", |
| 117 | + supportedAlgorithms: [-257], |
| 118 | + relyingPartyId: 'example.com', |
| 119 | + relyingPartyName: 'example', |
| 120 | + origin: 'https://example.com', |
| 121 | + }); |
| 122 | + }, |
| 123 | + }; |
| 124 | + }, |
| 125 | + }, |
| 126 | + }), |
| 127 | + Session.init() // initializes session features |
| 128 | + ] |
| 129 | +}); |
| 130 | +``` |
| 131 | + |
| 132 | +## Customising Credential Validation |
| 133 | + |
| 134 | +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: |
| 135 | + |
| 136 | +- **Relying Party ID**: The domain name (Relying Party ID) of your application that will be used for validating the credential. |
| 137 | +- **Origin**: The origin URL that the credential is generated on. Defaults to the origin of the request. |
| 138 | +- **Timeout**: The time in milliseconds that the user has to complete the credential validation process. Defaults to `6000`. |
| 139 | +- **User Verification**: Controls whether user verification (like PIN or biometrics) is required. Defaults to `preferred`. |
| 140 | + |
| 141 | +Below is an example of how you can customise the credential generation options. |
| 142 | + |
| 143 | +```ts |
| 144 | +import supertokens from "supertokens-node"; |
| 145 | +import Session from "supertokens-node/recipe/session"; |
| 146 | +import WebAuthn from "supertokens-node/recipe/webauthn"; |
| 147 | + |
| 148 | +supertokens.init({ |
| 149 | + framework: "express", |
| 150 | + supertokens: { |
| 151 | + // 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. |
| 152 | + connectionURI: "https://try.supertokens.com", |
| 153 | + // apiKey: <API_KEY(if configured)>, |
| 154 | + }, |
| 155 | + appInfo: { |
| 156 | + // learn more about this on https://supertokens.com/docs/session/appinfo |
| 157 | + appName: "<YOUR_APP_NAME>", |
| 158 | + apiDomain: "<YOUR_API_DOMAIN>", |
| 159 | + websiteDomain: "<YOUR_WEBSITE_DOMAIN>", |
| 160 | + apiBasePath: "/auth", |
| 161 | + websiteBasePath: "/auth" |
| 162 | + }, |
| 163 | + recipeList: [ |
| 164 | + WebAuthn.init({ |
| 165 | + override: { |
| 166 | + functions: (originalImplementation) => { |
| 167 | + return { |
| 168 | + ...originalImplementation, |
| 169 | + signInOptions: (input) => { |
| 170 | + return originalImplementation.signInOptions({ |
| 171 | + ...input, |
| 172 | + timeout: 10 * 1000, |
| 173 | + userVerification: "required", |
| 174 | + relyingPartyId: 'example.com', |
| 175 | + origin: 'https://example.com', |
| 176 | + }); |
| 177 | + }, |
| 178 | + }; |
| 179 | + }, |
| 180 | + }, |
| 181 | + }), |
| 182 | + Session.init() // initializes session features |
| 183 | + ] |
| 184 | +}); |
| 185 | +``` |
0 commit comments