Skip to content

fix(auth): return AuthInvalidJwtError from getClaims for expired JWT#2395

Merged
mandarini merged 1 commit into
masterfrom
fix/get-claims-expired-error
May 28, 2026
Merged

fix(auth): return AuthInvalidJwtError from getClaims for expired JWT#2395
mandarini merged 1 commit into
masterfrom
fix/get-claims-expired-error

Conversation

@mandarini
Copy link
Copy Markdown
Contributor

@mandarini mandarini commented May 22, 2026

Description

getClaims is documented to return { data, error }, but for expired JWTs it throws a plain Error('JWT has expired'). The throw originates in validateExp (lib/helpers.ts), which uses a generic Error. The outer catch in getClaims only converts AuthError instances to the return tuple, so the plain Error escapes and breaks the documented contract.

This PR wraps the single validateExp call site and rethrows as AuthInvalidJwtError, matching the pattern already used for invalid signatures a few lines below.

What changed?

  • packages/core/auth-js/src/GoTrueClient.ts: wrapped validateExp(payload.exp) in a try/catch that rethrows as AuthInvalidJwtError. The outer catch then surfaces it as { data: null, error }.
  • packages/core/auth-js/test/GoTrueClient.test.ts: updated the expired-JWT test to assert on the { data, error } return shape.

validateExp in lib/helpers.ts is intentionally not changed, so the standalone validateExp(0) browser test continues to pass.

Why was this change needed?

getClaims's signature-verification path already throws AuthInvalidJwtError and returns it via { data, error }. Expired tokens were the only error path violating the documented return type.

Closes #2394

Screenshots/Examples

Before:

try {
  await client.auth.getClaims()
} catch (e) {
  // e is a plain Error with message 'JWT has expired'
}

After:

const { data, error } = await client.auth.getClaims()
if (error) {
  // error.name === 'AuthInvalidJwtError'
  // error.message === 'JWT has expired'
}

Breaking changes

Small in practice. Anyone using the documented const { data, error } = await getClaims() pattern is unaffected (and actually benefits, since their code was previously crashing on expired tokens). The only group impacted is callers who wrote try/catch specifically to catch the raw Error thrown for expired tokens. Their migration is mechanical: move handling from the catch block to if (error). Error message is preserved and AuthInvalidJwtError is already exported from @supabase/auth-js.

  • This PR contains no breaking changes

Checklist

  • I have read the Contributing Guidelines
  • My PR title follows the conventional commit format: <type>(<scope>): <description>
  • I have run pnpm nx format to ensure consistent code formatting
  • I have added tests for new functionality (if applicable)
  • I have updated documentation (if applicable)

Additional notes

Landing as fix(auth) rather than fix(auth)!. The previous behavior contradicted the documented return type and the realistic blast radius is small (callers who built workarounds for the bug). Happy to relabel if reviewers prefer the louder signal.

@github-actions github-actions Bot added the auth-js Related to the auth-js library. label May 22, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 22, 2026

Open in StackBlitz

@supabase/auth-js

npm i https://pkg.pr.new/@supabase/auth-js@2395

@supabase/functions-js

npm i https://pkg.pr.new/@supabase/functions-js@2395

@supabase/postgrest-js

npm i https://pkg.pr.new/@supabase/postgrest-js@2395

@supabase/realtime-js

npm i https://pkg.pr.new/@supabase/realtime-js@2395

@supabase/storage-js

npm i https://pkg.pr.new/@supabase/storage-js@2395

@supabase/supabase-js

npm i https://pkg.pr.new/@supabase/supabase-js@2395

commit: cc1e9bc

@mandarini mandarini force-pushed the fix/get-claims-expired-error branch from d942277 to cc1e9bc Compare May 27, 2026 12:17
@mandarini mandarini marked this pull request as ready for review May 27, 2026 15:22
@mandarini mandarini requested review from a team as code owners May 27, 2026 15:22
@mandarini mandarini merged commit 0dc5f80 into master May 28, 2026
24 of 25 checks passed
@mandarini mandarini deleted the fix/get-claims-expired-error branch May 28, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth-js Related to the auth-js library.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getClaims is raising a generic Error for expired token

2 participants