fix: support subdomains for passkey#42
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR updates WebAuthn/passkey verification to support native iOS/macOS flows that report the bare RP ID origin (e.g. https://rxlab.app) rather than the server subdomain (e.g. https://auth.rxlab.app), and tightens native passkey OAuth flows by binding challenges to a validated redirect_uri.
Changes:
- Add
computeExpectedOrigins()and switch passkey verify routes to accept an array of expected origins (configured origin +https://<rpId>where applicable). - Require
redirect_urifor native passkey OAuth options requests; persist it in the Redis challenge and re-validate it during verify. - Add/adjust unit tests for expected origins and native passkey options/verify behavior.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/webauthn/config.ts | Adds computeExpectedOrigins() and exports expectedOrigins used by verification. |
| lib/webauthn/expected-origins.test.ts | Unit tests for expected-origins computation/deduping. |
| app/api/auth/passkey/register/verify/route.ts | Uses expectedOrigins for session-based registration verification. |
| app/api/auth/passkey/authenticate/verify/route.ts | Uses expectedOrigins for session-based authentication verification. |
| app/api/admin/passkey/register/verify/route.ts | Uses expectedOrigins for admin registration verification. |
| app/api/admin/passkey/authenticate/verify/route.ts | Uses expectedOrigins for admin authentication verification. |
| lib/validations/oauth.ts | Makes redirect_uri required for native passkey options requests. |
| lib/validations/oauth.test.ts | Updates schema tests for required redirect_uri. |
| lib/redis/index.ts | Extends WebAuthnChallengeData to include optional redirectUri. |
| lib/oauth/native-client.ts | Adds validateClientRedirect() (client existence + redirect allow-list). |
| app/api/oauth/passkey/authenticate/options/route.ts | Validates redirect_uri and stores it on the challenge. |
| app/api/oauth/passkey/authenticate/options/route.test.ts | New tests covering redirect URI validation + persistence. |
| app/api/oauth/passkey/authenticate/verify/route.ts | Re-validates stored redirectUri; uses expectedOrigins. |
| app/api/oauth/passkey/authenticate/verify/route.test.ts | Updates tests for redirect URI re-validation + expected origins array. |
| app/api/oauth/passkey/register/options/route.ts | Validates redirect_uri and stores it on the challenge. |
| app/api/oauth/passkey/register/options/route.test.ts | New tests covering redirect URI validation + persistence. |
| app/api/oauth/passkey/register/verify/route.ts | Re-validates stored redirectUri; uses expectedOrigins. |
| app/api/oauth/passkey/register/verify/route.test.ts | Updates tests for redirect URI re-validation behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+50
to
+61
| // Validate that a client exists and that the supplied redirect_uri is one | ||
| // the client has registered. Used by passkey native routes — instead of | ||
| // requiring `signInPermission === "all"`, we trust the client's registered | ||
| // redirect-URI allow-list (same gate authorization_code already uses, see | ||
| // app/api/oauth/authorize/route.ts:78-87). | ||
| // | ||
| // On unknown client: 401 invalid_client. | ||
| // On missing or unregistered redirect_uri: 400 invalid_request. | ||
| export async function validateClientRedirect(params: { | ||
| clientId: string; | ||
| redirectUri: string | undefined; | ||
| }): Promise<NativeClientCheck> { |
Comment on lines
+10
to
+24
| // Origins SimpleWebAuthn's verify functions will accept. | ||
| // | ||
| // Always includes the configured web origin (e.g. https://auth.rxlab.app). | ||
| // Also includes https://<rpID> (e.g. https://rxlab.app) when the rpID is a | ||
| // real registrable domain — native iOS/macOS apps using an Associated Domain | ||
| // of webcredentials:<rpID> set the WebAuthn origin in clientDataJSON to that | ||
| // bare-rpId URL, not the server's subdomain. Dedupes; skips for localhost. | ||
| export function computeExpectedOrigins( | ||
| configuredOrigin: string, | ||
| rpId: string, | ||
| ): string[] { | ||
| const set = new Set<string>([configuredOrigin]); | ||
| if (rpId && rpId !== "localhost" && rpId.includes(".")) { | ||
| set.add(`https://${rpId}`); | ||
| } |
Comment on lines
104
to
125
| @@ -118,6 +119,7 @@ export const passkeyAuthVerifyRequestSchema = z.object({ | |||
| // POST /api/oauth/passkey/register/options | |||
| export const passkeyRegisterOptionsRequestSchema = z.object({ | |||
| client_id: z.string().min(1, "client_id is required"), | |||
| redirect_uri: z.string().min(1, "redirect_uri is required"), | |||
| username: z.string().email("username must be a valid email address"), | |||
| name: z.string().min(1).max(64).optional(), | |||
| }); | |||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.