Skip to content

feat(auth-js): Export utility for parsing auth error redirects & fix detection gap #2405

@lucas-spin

Description

@lucas-spin

Feature description

As a developer using @supabase/auth-js, I want a reliable way to detect and parse auth error redirects so that I can surface meaningful error messages to users without hand-rolling URL parsing logic.

Currently, when Supabase Auth redirects with error params (e.g. expired magic link, denied OAuth), the only way to catch the error is by awaiting supabase.auth.initialize(). The onAuthStateChange callback receives ('INITIAL_SESSION', null) with no error object — making it impossible to distinguish "no session exists" from "auth redirect failed with an error".

Additionally, _isImplicitGrantCallback only checks params.error_description (not params.error) in its detection condition. This means a redirect with ?error=access_denied but no error_description field won't be recognized as an auth callback, and the error is silently dropped.

Suggested solution

In library auth-js we could provide the following:

1. Export a parseAuthErrorFromURL utility:

// New export from @supabase/auth-js
export function parseAuthErrorFromURL(
  url?: string
): { error: string; error_code: string; error_description: string } | null {
  const href = url || (isBrowser() ? window.location.href : '')
  if (!href) return null

  const params = parseParametersFromURL(href) // already handles both hash + query
  
  if (params.error || params.error_description || params.error_code) {
    return {
      error: params.error || 'unspecified_error',
      error_code: params.error_code || 'unspecified_code',
      error_description: params.error_description || '',
    }
  }
  return null
}

This leverages the existing parseParametersFromURL (which already reads both #hash and ?query) and gives developers a clean, typed API for detecting auth errors in redirect URLs.

2. Fix the _isImplicitGrantCallback detection gate:

// Current (incomplete):
return Boolean(params.access_token || params.error_description)

// Proposed fix:
return Boolean(params.access_token || params.error || params.error_description)

This ensures redirects with ?error=access_denied (no error_description) are still recognized as auth callbacks. Prior art: #1697 touched this same gate for a different reason (false positives on non-Supabase OAuth).

Alternative

An alternative would be adding an error parameter to the onAuthStateChange callback signature:

supabase.auth.onAuthStateChange((event, session, error?) => {
  if (event === 'INITIAL_SESSION' && error) {
    // Now we can distinguish "no session" from "redirect error"
  }
})

This would be the ideal long-term fix but is a larger API surface change. The exported utility is a non-breaking first step that gives developers immediate relief.

Additional context

Real-world impact: In our production app, we had to implement manual dual-parsing (both URLSearchParams(location.search) and URLSearchParams(location.hash.slice(1))) in our password reset flow to catch error params that the client didn't surface. Our sign-up flow only checks query string and misses hash-delivered errors entirely.

Detection gate edge case: The OAuth 2.0 spec allows error responses with just error (no error_description). RFC 6749 §4.1.2.1 defines error_description as OPTIONAL. The current gate condition means spec-compliant error redirects without a description are silently ignored.

Validations

  • I have read and agree to the Code of Conduct
  • I have read the Contributing Guidelines
  • I have checked for existing issues that describe this proposal
  • This is not a duplicate of any existing issue

Metadata

Metadata

Assignees

Labels

auth-jsRelated to the auth-js library.bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions