Add structured error handling with AuthErrorCode#284
Draft
erquhart wants to merge 22 commits into
Draft
Conversation
Cover all error paths with exact message/behavior assertions: - Credentials: InvalidSecret, InvalidAccountId, TooManyFailedAttempts - OTP: Could not verify code (wrong code, expired, rate limited) - Refresh: silent tokens null (expired token, expired session) - Code exchange: silent tokens null (invalid magic link code) - Credentials authorize null: silent tokens null - OAuth callback failure: 302 redirect without code param - Password validation: Invalid password Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces the OAuth callback test with a realistic token exchange failure flow, and adds tests for duplicate sign-up, missing password params, and invalid provider name. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace silent null returns and generic throws with structured error
codes throughout the auth flow. Mutations return { error: AuthErrorCode }
instead of null, the signIn action propagates errors to clients via an
optional error field, and OAuth callback failures redirect with
?error=OAUTH_FAILED. Adds onError server callback for observability
and surfaces errors in React/Next.js clients.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…changes
Revert client-side error state (React, Next.js) and keep error handling
server-side only. handleEmailAndPhoneProvider now throws with structured
error codes instead of returning them. The signIn action wraps signInImpl
in try/catch: when onError is configured, auth errors are caught and
{tokens: null} is returned; without onError, errors re-throw (backwards
compatible). Return-based errors (refresh, code-exchange) call onError
observationally.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All auth errors now route through onError (defaulting to legacyOnAuthError for backwards compat). The `thrown` flag lets handlers distinguish errors that originally threw from those that were silently returned. defaultOnAuthError throws ConvexError with structured data for all errors except refresh failures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… handling Replaces the boolean `thrown` property in onError args with `legacyMessage: string | null`. The call sites that invoke onError already know the original legacy error string, so they set it directly. legacyOnAuthError simply throws when non-null, resolving the RATE_LIMITED ambiguity without needing separate error codes. - Add AuthError class carrying both structured code and legacyMessage - Replace extractAuthErrorCode with extractAuthError returning both fields - handleEmailAndPhoneProvider throws AuthError with "Could not verify code" - retrieveAccount throws AuthError with original credential strings - legacyMessage is @deprecated from day one; falls off without API impact Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
defaultOnAuthError now throws plain Error (stripped in production) instead of ConvexError. Developers must explicitly opt in to exposing structured error data to clients via ConvexError in their own onError callback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests for AuthErrorCode vocabulary, legacyOnAuthError behavior (throws on non-null legacyMessage, silent on null), and defaultOnAuthError behavior (opaque Error throws, silent for refresh/session, ignores legacyMessage). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move onError resolution from inside the signIn action to the top of convexAuth() so it's shared by both the signIn action and OAuth callback. The OAuth callback now always calls onError instead of conditionally checking config.callbacks?.onError. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename onError → handleAuthError (with deprecation warning for old name).
The callback now returns void | AuthErrorCode instead of only void:
returning a code includes it in the response as { tokens: null, error },
returning void gives a silent { tokens: null }, and throwing preserves
backwards-compatible behavior. defaultOnAuthError returns codes with
enumeration prevention (ACCOUNT_NOT_FOUND/ACCOUNT_DELETED → INVALID_CREDENTIALS).
Surface error field through React client signIn return and Next.js proxy.
Export AuthErrorCode from @convex-dev/auth/react.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…warning The auth context is implicit from convexAuth() callbacks. onError was never released so no deprecation warning is needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
commit: |
The test triggers a structured auth error (INVALID_CREDENTIALS) through the Next.js proxy and asserts the client receives the clean error code. This test is expected to fail — the proxy extracts (error as Error).message from a ConvexError, which yields a JSON string instead of the structured code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The proxy was extracting (error as Error).message from ConvexErrors, which yields a JSON string instead of structured data. Now the proxy detects ConvexError and serializes its .data with an isConvexError flag, and the client reconstructs the ConvexError on the other side. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create dedicated error-handling.mdx page documenting structured error codes, the handleError callback, and OAuth error handling. Fix inaccuracy in passwords.mdx (signIn returns an object, not a boolean). Add cross-reference callouts to provider pages and sections in advanced.mdx and debugging.mdx. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vercel blocks deployments using next-mdx-remote 4.4.1. Add npm override to use v6.0.0 while remaining on nextra 2.x. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
04bb74a to
205ce39
Compare
- Add JSDoc descriptions to all AuthErrorCode members - Add @param tags to legacyOnAuthError and defaultOnAuthError - Remove duplicate AuthErrorCode section (type alias) via post-processing - Fix AuthErrorCode anchor references after duplicate removal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add prerequisite blockquote and user-perspective intro to error-handling page - Wrap setup flow in <Steps> component to match config page patterns - Normalize callout wording across config pages (passwords, email, otps, oauth) - Split long compound sentence in passwords.mdx verification section - Use active voice in debugging.mdx error codes section - Tighten API reference JSDoc: standalone import examples, compact descriptions - Redirect non-basePath URLs to /auth/* in dev for convenience Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers both handleError paths: throwing ConvexError (existing) and returning an error code via result.error (new). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a second convexAuth() instance configured with defaultOnAuthError and tests that the signIn pipeline correctly returns error codes instead of throwing: wrong password returns INVALID_CREDENTIALS, non-existent account maps ACCOUNT_NOT_FOUND to INVALID_CREDENTIALS, and successful sign-in has no error field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.
Summary
AuthErrorCodevocabulary (12 structured error codes) andAuthErrorclass for internal error propagationhandleErrorcallback inconvexAuth({ callbacks: { ... } })that controls what error info reaches the clientAuthErrorCode→ included in response as{ tokens: null, error: code }void→ silent{ tokens: null }ConvexError, or plainErrorstripped in production)legacyOnAuthErrorpreserving exact backwards-compatible throw behaviordefaultOnAuthErroras the recommended handler: returns codes with user enumeration prevention (ACCOUNT_NOT_FOUND/ACCOUNT_DELETED→INVALID_CREDENTIALS)errorfield through React clientsignIn()return and Next.js proxyAuthErrorCodefrom@convex-dev/auth/reactfor client-side comparisonTest plan
structuredErrors.test.ts: unit tests fordefaultOnAuthErrorreturn values, enumeration mapping, silent refresh failureserrorHandling.test.ts: integration tests for legacy throw behavior, OAuth redirect without error paramIssues
Closes #124 — structured error codes for password/credential flows
Closes #229 — preserve ConvexError through Next.js proxy
Related #54 — adds structured error return path; doesn't cover all auth error surfaces (e.g. OAuth redirect URI mismatches)
Related #65 — standard auth failures now return codes instead of throwing; custom errors thrown from authorize() still go through the old throw path
Related #165 — user-thrown ConvexError from createOrUpdateUser now preserved through Next.js proxy; non-Next.js passthrough unchanged