Sign In with WebAuthn
Learn about WebAuthn and Security Keys
WebAuthn security key passkey FIDO2 biometric fingerprint face ID YubiKey passwordless PKCEFollow this guide to sign in users with security keys and the WebAuthn API.
Examples of security keys:
- Passkeys
- Windows Hello
- Apple Touch ID
- Apple Face ID
- Yubico security keys
- Android Fingerprint sensors
You can read more about this feature in our blog post
Configuration
Section titled “Configuration”Enable the Security Key sign-in method in the Nhost Dashboard under Settings -> Sign-In Methods -> Security Keys.
You need to make sure you also set a valid client URL under Settings -> Authentication -> Client URL.
Sign Up
Section titled “Sign Up”Users must use an email address to sign up with a security key. When email verification is enabled, pass a codeChallenge for PKCE:
import { generatePKCEPair } from '@nhost/nhost-js/auth';import { startRegistration } from '@simplewebauthn/browser';
const { verifier, challenge } = await generatePKCEPair();localStorage.setItem('nhost_pkce_verifier', verifier);
// Step 1: Request registration challengeconst response = await nhost.auth.signUpWebauthn({ email: 'joe@example.com', options: { redirectTo: `${window.location.origin}/verify`, },});
// Step 2: Create credential with authenticatorconst credential = await startRegistration({ optionsJSON: response.body });
// Step 3: Verify credential with PKCEawait nhost.auth.verifySignUpWebauthn({ credential, options: { redirectTo: `${window.location.origin}/verify`, }, nickname: 'My Security Key', codeChallenge: challenge,});If email verification is required, the user will receive a verification email. After clicking the link, the authorization code is exchanged for a session.
Sign Up Flow
Section titled “Sign Up Flow”sequenceDiagram autonumber actor U as User participant C as Client participant A as Nhost Auth participant G as Authenticator participant E as SMTP Server C->>C: Generate PKCE pair (verifier + challenge) C->>C: Store verifier in localStorage U->>+A: POST /signup/webauthn A->>A: Create tentative user A->>-U: Challenge U->>+G: Sign challenge G->>-U: Signed challenge U->>+A: POST /signup/webauthn/verify Note right of U: credential, codeChallenge A->>A: Verify signed challenge A->>A: Add security key alt No email verification required A->>-U: Session (access + refresh tokens) else Email verification required A->>A: Generate ticket (stores codeChallenge) A-)E: Send verification email A->>U: OK (no session) E-)U: Receive email U->>+A: GET /verify (follow email link) A->>A: Verify email A->>A: Generate authorization code A->>-C: Redirect with ?code=... C->>C: Consume verifier from localStorage C->>+A: POST /token/exchange Note right of C: code + codeVerifier A->>A: Validate S256(codeVerifier) == codeChallenge A->>-C: Session (access + refresh tokens) endSign In
Section titled “Sign In”Once a user signed up with a security key and verified their email if needed, they can use it to sign in.
await nhost.auth.signIn({ email: 'joe@example.com', securityKey: true,});Sign In Flow
Section titled “Sign In Flow”sequenceDiagram autonumber actor U as User participant A as Nhost Auth participant G as Authenticator U->>+A: POST /signin/webauthn alt Email not verified or user disabled A->>U: ERROR else Email verified and user enabled A->>-U: Challenge end U->>+G: Sign challenge G->>-U: Signed challenge U->>+A: POST /signin/webauthn/verify A->>A: Verify signed challenge alt Email not verified or user disabled A->>U: ERROR else Valid A->>-U: Session (access + refresh tokens) endAdd a Security Key
Section titled “Add a Security Key”Any signed-in user with a verified email can add a security key to their user account. It’s possible to add multiple security keys.
const { key, error } = await nhost.auth.addSecurityKey('My iPhone');Add Security Key Flow
Section titled “Add Security Key Flow”sequenceDiagram autonumber actor U as User participant A as Nhost Auth participant G as Authenticator U-->A: Authenticated U->>+A: POST /user/webauthn/add A->>-U: Challenge U->>+G: Sign challenge G->>-U: Signed challenge U->>+A: POST /user/webauthn/verify A->>A: Verify signed challenge A->>A: Add security key A->>-U: OKList or Remove Security Keys
Section titled “List or Remove Security Keys”To list and remove security keys, use GraphQL and set permissions on the auth.security_keys table:
query securityKeys($userId: uuid!) { authUserSecurityKeys(where: { userId: { _eq: $userId } }) { id nickname }}To remove a security key:
mutation removeSecurityKey($id: uuid!) { deleteAuthUserSecurityKey(id: $id) { id }}