Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

feat: mfa with webauthn support#1118

Merged
hf merged 29 commits intomasterfrom
bewinxed/add-mfa-webauthn
Sep 24, 2025
Merged

feat: mfa with webauthn support#1118
hf merged 29 commits intomasterfrom
bewinxed/add-mfa-webauthn

Conversation

@Bewinxed
Copy link
Collaborator

@Bewinxed Bewinxed commented Sep 13, 2025

What kind of change does this PR introduce?

Feature - This PR introduces YubiKey support for Multi-Factor Authentication (MFA) via WebAuthn, enabling users to authenticate with hardware security keys.

What is the current behavior?

Currently, Supabase Auth JS supports two MFA methods:

  • TOTP (Time-based One-Time Password) authenticators
  • SMS-based verification

What is the new behavior?

This PR adds full WebAuthn support to the authentication library, the defaults enable yubikey support at the moment, but it allows the user to override some parameters client-side to use other types of passkey methods.

The PR adds the 'webauthn' factor type, to listFactors, enroll(), challenge(), and verify()

(De)serialization of the webauthn reponse/credential object is done behind the scenes via dedicated objects.

it also adds a new experimental namespace .mfa.webauthn which has a .register() and .authenticate() methods, these methods allows single click yubikey 2FA addition with a single function call.

additionally, we have webauthn.{enroll|challenge|verify}(), which abstract away some of the logic surrounding enrollment, interaction with the verifier, and have defaults for factortype etc.

Two ways to use the new api:

Single Step

const { data, error } = await client.mfa.webauthn.register({
				friendlyName: `Security Key ${new Date().toLocaleDateString()}`,
				rpId: window.location.hostname,
				rpOrigins: [window.location.origin]
			}, {
				authenticatorSelection: {
					authenticatorAttachment: 'platform',
					residentKey: 'discouraged',
					userVerification: 'discouraged',
					requireResidentKey: false
				}
			});

			if (error) throw error;

			console.log(data); // <- session

Multi Step Composition

const { enroll, challenge, verify } = new WebAuthnApi(client);
		return enroll({
			friendlyName: params.friendlyName
		})
			.then(async ({ data, error }) => {
				if (!data) {
					throw error;
				}
				console.log(`enrolled factor, id: ${data.id}`, 'success');
				return await challenge({
					factorId: data?.id,
					webauthn: {
						rpId: params.rpId,
						rpOrigins: params.rpOrigins
					},
					signal: undefined
				});
			})
			.then(async ({ data, error }) => {
				if (!data) {
					throw error;
				}
				console.log(`challenged factor, id: ${data.factorId}`, 'success');
				return await verify({
					factorId: data.factorId,
					challengeId: data.challengeId,
					webauthn: {
						rpId: params.rpId,
						rpOrigins: params.rpOrigins,
						type: data.webauthn.type,
						credential_response: data.webauthn.credential_response
					}
				});
			})
			.then(({ data, error }) => {
				if (!data) {
					throw error;
				}
				console.log(`verified factor, id: ${data.access_token}`, 'success');
				return data;
			});

Additional context

While this PR focuses on YubiKey support, the architecture is designed to accommodate additional authenticator types in future releases (platform authenticators, passkeys, etc.) without requiring significant refactoring.

I've added webauthn.dom.ts and webauthn.errors.ts which attempt to augment the typescript interfaces for webauthn since they are out of date and there are some new features that its not aware of yet but are publicly available in all major browsers.

For all such types, and due to the complexity of the API, I've added comprehensive jsdocs for each parameter with reference to the w3a spec for reference on their usage.

in all webauthn related methods, I've added the ability to override any of the parameters we pass by default to the credentials.{get|create}() method for convenience.

This PR is dependent on my previous PR for streamlining types #1116

and this PR for auth supabase/auth#2163

@github-actions
Copy link
Contributor

github-actions bot commented Sep 13, 2025

🚀 Preview Release Status

false


Last updated: 2025-09-24T14:20:00Z

Copy link
Contributor

@hf hf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A huge amount of effort but is great! Left comments on Slack for minor improvements.

@hf hf changed the title feat: Webauthn support feat: mfa with webauthn support Sep 24, 2025
@hf hf merged commit 1cbd43e into master Sep 24, 2025
6 of 8 checks passed
@hf hf deleted the bewinxed/add-mfa-webauthn branch September 24, 2025 14:28
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants