Skip to content

Passwordless DB Implementation#2721

Merged
Piyush-85 merged 15 commits into
mainfrom
feat/passwordless-db-types-errors
Jul 6, 2026
Merged

Passwordless DB Implementation#2721
Piyush-85 merged 15 commits into
mainfrom
feat/passwordless-db-types-errors

Conversation

@Piyush-85

@Piyush-85 Piyush-85 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

📋 Changes

Adds passwordless OTP authentication for database connections (Early Access). This is a two-step embedded flow — no redirect required — that works with any
Auth0 database connection configured with email_otp or phone_otp.

Flow:

  1. Call challengeWithEmail or challengeWithPhoneNumber → Auth0 sends an OTP and returns an opaque authSession
  2. Call loginWithOtp with the authSession and user-entered OTP → tokens are exchanged and a session is created automatically

Server-side usage (App Router):

import { auth0 } from '@/lib/auth0';

const challenge = await auth0.passwordless.challengeWithEmail({
  email: 'user@example.com',
  connection: 'my-db-connection',
});

await auth0.passwordless.loginWithOtp({
  authSession: challenge.authSession,
  otp: '123456',
});

Client-side usage:

  import { passwordless } from '@auth0/nextjs-auth0/client';

  const challenge = await passwordless.challengeWithEmail({
    email: 'user@example.com',
    connection: 'my-db-connection',
  });

  await passwordless.loginWithOtp({
    authSession: challenge.authSession,
    otp: '123456',
  });

Types exported:

  • PasswordlessDbChallengeEmailOptions — { email, connection, allowSignup? }
  • PasswordlessDbChallengePhoneOptions — { phoneNumber, connection, deliveryMethod?, allowSignup? }
  • PasswordlessDbGetTokenOptions — { authSession, otp }
  • PasswordlessDbChallenge — { authSession: string } (opaque token returned by challenge)
  • PasswordlessDbDeliveryMethod — 'text' | 'voice'

Errors exported:

  • PasswordlessDbChallengeError — thrown on challenge failures (code: 'passwordless_challenge_error')
  • PasswordlessDbGetTokenError — thrown on token exchange failures (code: 'passwordless_login_error'); when MFA is required, error.cause.error === 'mfa_required' with mfa_token for use with auth0.mfa

What's included:

  • challengeWithEmail / challengeWithPhoneNumber on both server and client — request an OTP; delivery_method only forwarded when explicitly provided;
    allowSignup defaults to false
  • loginWithOtp — exchanges authSession + OTP for tokens, creates session, sets cookie automatically
  • Two new route handlers: POST /auth/passwordless/otp/challenge and POST /auth/passwordless/otp/token
  • DPoP and mTLS support via shared openid-client configuration
  • Non-breaking additive change — existing passwordless.start / passwordless.verify flows unchanged

📎 References

🎯 Testing

Unit and integration tests cover: email/phone challenge, delivery_method omitted when not provided, allowSignup default, wrong OTP, expired auth_session, blocked user (200-always contract), discovery failure, MFA (mfa_required → 403 with encrypted token, no Set-Cookie), DPoP nonce retry, invalid_issuer mapping, and 200 with non-JSON body. Both AuthClient server methods and client-side fetch wrappers are tested end-to-end with MSW.

@Piyush-85 Piyush-85 requested a review from a team as a code owner June 26, 2026 05:15
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds passwordless DB OTP types and errors, wires new challenge/token routes through client and server passwordless APIs, and adds flow tests for challenge, token exchange, MFA handling, and DPoP nonce retry behavior.

Changes

Passwordless DB OTP flow

Layer / File(s) Summary
Challenge and token types
src/types/passwordless-db.ts, src/types/passwordless.ts, src/types/index.ts, src/server/client.ts, src/server/dynamic-base-url.test.ts, src/test/defaults.ts, src/test/mcd-test-fixtures.ts
Defines OTP delivery, challenge, and token types, then re-exports them and adds matching route defaults.
Passwordless DB errors
src/errors/passwordless-db-errors.ts, src/errors/index.ts
Defines the passwordless DB error base class, the challenge and token error classes, and the root error re-export.
Passwordless client and server methods
src/client/passwordless/index.ts, src/server/passwordless/server-passwordless-client.ts, src/types/passwordless.ts
Adds DB OTP methods to the public client surface and implements client/server challenge and login flows.
Server routes and core handlers
src/server/auth-client.ts, src/server/client.ts, src/server/dynamic-base-url.test.ts, src/server/passwordless-db.flow.test.ts, src/server/passwordless-db-server.flow.test.ts
Wires request routing, core OTP exchange handlers, route defaults, and server-side flow coverage for challenge, token, MFA, and DPoP behavior.
Client flow tests
src/client/passwordless/passwordless-db-client.flow.test.ts
Exercises the client DB OTP challenge and token flows with MSW, including success cases, error mapping, and mfa_required handling.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • auth0/nextjs-auth0#2633: Extends the same passwordless client surface with the DB OTP methods introduced here.
  • auth0/nextjs-auth0#2719: Overlaps with the same DB passwordless client methods, error wiring, and flow tests.
  • auth0/nextjs-auth0#2727: Touches src/server/auth-client.ts around token endpoint routing that intersects with the new passwordless DB token exchange flow.

Suggested reviewers: tusharpandey13, pmathew92

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the main change, clearly indicating the new Passwordless DB feature.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/passwordless-db-types-errors

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

codecov-commenter commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.09256% with 89 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.02%. Comparing base (9041e19) to head (37a88df).

Files with missing lines Patch % Lines
.../server/passwordless/server-passwordless-client.ts 45.90% 33 Missing ⚠️
src/server/auth-client.ts 90.68% 27 Missing ⚠️
src/client/passwordless/index.ts 74.71% 22 Missing ⚠️
src/errors/passwordless-db-errors.ts 83.72% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2721      +/-   ##
==========================================
- Coverage   88.30%   88.02%   -0.29%     
==========================================
  Files          77       79       +2     
  Lines       10514    11011     +497     
  Branches     2176     2277     +101     
==========================================
+ Hits         9284     9692     +408     
- Misses       1186     1275      +89     
  Partials       44       44              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/passwordless/index.ts`:
- Around line 144-160: The public PasswordlessClient methods challengeWithEmail,
challengeWithPhoneNumber, and loginWithOtp currently throw generic Error, which
exposes unstable runtime failures to consumers. Either remove these stubs from
the runtime surface until they are implemented, or replace the throws with the
proper Auth0 SDK error types that include a stable error.code for branching.
Update the PasswordlessClient implementation so these methods no longer return a
plain generic error and align with the SDK’s error-handling contract.

In `@src/server/passwordless/server-passwordless-client.ts`:
- Around line 175-191: The public passwordless methods on
ServerPasswordlessClient are still unusable stubs that only throw a generic
Error, so replace them with real server-side implementations or with SDK-style
Auth0 errors that expose error.code. Update challengeWithEmail,
challengeWithPhoneNumber, and loginWithOtp to follow the same error contract
used elsewhere in the client so callers can handle failures via error.code
instead of instanceof checks.

In `@src/types/passwordless.ts`:
- Around line 198-203: Update the API docs in passwordless.ts to reference the
exported error class actually defined in this change set,
PasswordlessDbGetTokenError, instead of the old PasswordlessLoginError name.
Keep the surrounding description for the authSession/OTP exchange behavior, and
make sure any mentions in the interface comment or related docs point consumers
to the correct error symbol for handling failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bce9e10f-2095-44a3-9fef-283e7818ff76

📥 Commits

Reviewing files that changed from the base of the PR and between 87fd32b and c6b03fe.

📒 Files selected for processing (7)
  • src/client/passwordless/index.ts
  • src/errors/index.ts
  • src/errors/passwordless-db-errors.ts
  • src/server/passwordless/server-passwordless-client.ts
  • src/types/index.ts
  • src/types/passwordless-db.ts
  • src/types/passwordless.ts

Comment thread src/client/passwordless/index.ts Outdated
Comment thread src/server/passwordless/server-passwordless-client.ts Outdated
Comment thread src/types/passwordless.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
src/server/passwordless-db.flow.test.ts (1)

64-86: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract a shared MSW body-capture helper to reduce duplication.

The capturedBody/capturedParams + server.use(http.post(...)) pattern is repeated nearly identically across ~7 tests in this file. A small helper (e.g., captureRequestBody(url)) would cut boilerplate and reduce drift risk as more assertions are added.

Also applies to: 103-120, 141-157, 159-176, 178-194, 281-307

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/passwordless-db.flow.test.ts` around lines 64 - 86, The
request-body capture setup is duplicated across multiple passwordless-db tests,
so extract a shared MSW helper to centralize the repeated
server.use(http.post(...)) pattern. Create a small utility around request.json()
that captures the body/params for a given URL, then use it from the affected
authClient.passwordlessDbOtpChallenge and related tests so the assertions stay
the same but the boilerplate is removed.
src/server/passwordless-db-server.flow.test.ts (2)

162-176: 📐 Maintainability & Code Quality | 🔵 Trivial

Weak assertion for missing-field validation tests.

expect(body.error).toBeTruthy() only confirms some error field exists, not the correct error code (e.g. missing_identifier vs. a generic validation error). Asserting the exact error value would make these tests meaningfully catch regressions in field-validation error codes.

Also applies to: 301-331

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/passwordless-db-server.flow.test.ts` around lines 162 - 176, The
missing-field validation tests in authClient.handler only assert that body.error
exists, so they can miss regressions in the actual validation code. Update the
affected cases in passwordless-db-server.flow.test.ts to assert the exact
expected error value instead of toBeTruthy, using the same pattern for the other
related tests around the challenge request so they verify the specific
field-validation error code returned by the handler.

103-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Repeated NextRequest construction boilerplate across ~14 tests.

Every test rebuilds the same new NextRequest(url, {method: "POST", body, headers}) shape. A helper like postRequest(path, body) would shrink each test to a couple of lines and make the intent (payload differences) clearer at a glance.

Handles the server route POST /auth/passwordless/otp/challenge by dispatching to AuthClient.passwordlessDbOtpChallenge and mapping validation/upstream failures to HTTP responses.
Based on this contract, the flow test correctly exercises the request/response shapes described in the handler.

Also applies to: 128-138, 147-154, 163-170, 191-201, 215-225, 251-261, 282-292, 302-309, 318-325, 353-363, 383-393, 419-429, 459-469

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/passwordless-db-server.flow.test.ts` around lines 103 - 113,
Repeated NextRequest construction is duplicated across the passwordless DB
server flow tests, making the cases noisy and harder to scan. Add a small helper
such as postRequest(path, body) in passwordless-db-server.flow.test.ts that
builds the common POST NextRequest shape with DEFAULT.appBaseUrl and JSON
headers, then replace each inline construction in the affected tests with that
helper while keeping only the payload-specific parts visible.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/passwordless/index.ts`:
- Around line 159-161: The wrapped union type in the Passwordless client options
declaration is not following the lint-required formatting. Update the type
annotation in the passwordless index module so the union members for
PasswordlessDbChallengeEmailOptions and PasswordlessDbChallengePhoneOptions are
formatted according to the project’s lint style, using the same declaration
around the options field and keeping the type equivalent.
- Around line 196-197: The `PasswordlessDbChallenge` success handling in
`src/client/passwordless/index.ts` should convert malformed success responses
into `PasswordlessDbChallengeError` instead of leaking a raw `response.json()`
parse failure or returning a result without `authSession`. Update the logic
around the `data = await response.json()` and returned object so both non-JSON
bodies and JSON payloads missing `authSession` are caught and wrapped in the SDK
error type, preserving the existing `PasswordlessDbChallengeError` contract for
callers.

In `@src/server/auth-client.ts`:
- Around line 5520-5524: The `passwordlessDbOtpChallenge` method’s `options`
union type is not formatted in the lint-approved shape, causing the Prettier
check to fail. Reformat this signature in `auth-client.ts` so the
`PasswordlessDbChallengeEmailOptions | PasswordlessDbChallengePhoneOptions`
union is emitted by the project formatter, and use the surrounding
`passwordlessDbOtpChallenge` declaration to locate the change.
- Around line 5635-5652: The passwordless DB OTP token exchange in
passwordlessDbGetToken is bypassing the mTLS endpoint alias, unlike
passwordlessVerify, mfaVerify, customTokenExchange, and getConnectionTokenSet.
Update this flow to resolve authorizationServerMetadata through
this.withMtlsEndpoint(...) before calling oauth.genericTokenEndpointRequest and
oauth.processGenericTokenEndpointResponse, so useMtls routes the request to
mtls_endpoint_aliases.token_endpoint instead of the standard token_endpoint.
- Around line 5615-5617: Remove the manual client_secret append from the
request-building logic in auth-client.ts so the client auth is handled only by
getClientAuth(). Update the code around the client_secret parameter assembly to
avoid sending both client_assertion and client_secret when a signing key is
configured, and keep the existing client authentication flow intact.

---

Nitpick comments:
In `@src/server/passwordless-db-server.flow.test.ts`:
- Around line 162-176: The missing-field validation tests in authClient.handler
only assert that body.error exists, so they can miss regressions in the actual
validation code. Update the affected cases in
passwordless-db-server.flow.test.ts to assert the exact expected error value
instead of toBeTruthy, using the same pattern for the other related tests around
the challenge request so they verify the specific field-validation error code
returned by the handler.
- Around line 103-113: Repeated NextRequest construction is duplicated across
the passwordless DB server flow tests, making the cases noisy and harder to
scan. Add a small helper such as postRequest(path, body) in
passwordless-db-server.flow.test.ts that builds the common POST NextRequest
shape with DEFAULT.appBaseUrl and JSON headers, then replace each inline
construction in the affected tests with that helper while keeping only the
payload-specific parts visible.

In `@src/server/passwordless-db.flow.test.ts`:
- Around line 64-86: The request-body capture setup is duplicated across
multiple passwordless-db tests, so extract a shared MSW helper to centralize the
repeated server.use(http.post(...)) pattern. Create a small utility around
request.json() that captures the body/params for a given URL, then use it from
the affected authClient.passwordlessDbOtpChallenge and related tests so the
assertions stay the same but the boilerplate is removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 66f476da-29ac-48db-90c5-64a947ac9bcc

📥 Commits

Reviewing files that changed from the base of the PR and between 653f976 and 7def428.

📒 Files selected for processing (11)
  • src/client/passwordless/index.ts
  • src/client/passwordless/passwordless-db-client.flow.test.ts
  • src/server/auth-client.ts
  • src/server/client.ts
  • src/server/dynamic-base-url.test.ts
  • src/server/passwordless-db-server.flow.test.ts
  • src/server/passwordless-db.flow.test.ts
  • src/server/passwordless/server-passwordless-client.ts
  • src/test/defaults.ts
  • src/test/mcd-test-fixtures.ts
  • src/types/passwordless-db.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/types/passwordless-db.ts

Comment thread src/client/passwordless/index.ts Outdated
Comment thread src/client/passwordless/index.ts Outdated
Comment thread src/server/auth-client.ts
Comment thread src/server/auth-client.ts Outdated
Comment thread src/server/auth-client.ts
@Piyush-85 Piyush-85 changed the title Passwordless DB connections - types and errors Passwordless DB Implementation Jul 1, 2026
Comment thread src/server/auth-client.ts Outdated
Comment thread src/server/auth-client.ts
@Piyush-85 Piyush-85 merged commit 34e51a5 into main Jul 6, 2026
9 checks passed
@Piyush-85 Piyush-85 deleted the feat/passwordless-db-types-errors branch July 6, 2026 11:28
@Piyush-85 Piyush-85 mentioned this pull request Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants