Skip to content

parity(auth): implement concurrent PKCE flow support (flow id) [from supabase-js] #1648

Description

@grdsdev

Warning

Auto-generated parity issue — may be a false positive.

This issue was created automatically by /sync-sdk-parity from a heuristic
analysis of recent supabase-js commits. The tooling has limited insight
into language-specific idioms and may have:

  • misidentified a JS-only change as cross-language relevant,
  • missed an existing implementation in this SDK under a different name,
  • or proposed an API shape that doesn't fit this language's conventions.

It is the SDK author's responsibility to validate the need before
implementing.
If this change does not apply to this SDK, please close the
issue with a short note explaining why.


SDK Parity: Dart implementation needed

A change was made in supabase-js that needs to be implemented in this repository for SDK parity.

Reference Implementation (supabase-js)

What Changed

supabase-js used to store a single PKCE code verifier under one fixed storage key. Starting two PKCE flows concurrently (e.g. two sign-in tabs, or an OAuth flow started while a password-recovery flow is pending) would silently overwrite the earlier flow's verifier, breaking whichever flow completed second. The fix introduces a per-flow "flow id": signInWithOAuth, signInWithOtp, signInWithSSO, resend, updateUser, resetPasswordForEmail, and linkIdentity now return a flowId in their response data, and verifiers are stored in a bounded ring of up to 5 concurrent slots keyed by that id (oldest evicted when the limit is exceeded). exchangeCodeForSession(authCode, { flowId }) accepts an optional flow id to select the correct verifier; without one it falls back to the most-recently-stored verifier (old single-flow behavior, kept for backward compatibility). An experimental flag experimental.appendPkceFlowIdToRedirects can append the flow id as a reserved sb_flow_id query parameter to the redirect URL so a server-side callback handler can read it back automatically instead of having to thread the flowId through its own channel.

Code Reference

export const pkceVerifierSlotKey = (storageKey: string, flowId: string) =>
  `${storageKey}-flow-${flowId}-code-verifier`

async function exchangeCodeForSession(
  authCode: string,
  options?: { flowId?: string }
): Promise<AuthTokenResponse> { /* looks up verifier by flowId, falls back to legacy single key */ }

Implementation Guidance

Expected API Surface

supabase-flutter's gotrue_client.dart currently stores the verifier under one fixed key (${defaultStorageKey}-code-verifier per prior investigation) and exchangeCodeForSession(String authCode) takes no flow id. Add a flowId field to sign-in response types, store verifiers keyed by flow id (bounded ring, e.g. max 5 pending), and add an optional named flowId parameter to exchangeCodeForSession. Falling back to the most recent verifier when no flow id is given keeps existing callers working unchanged.

Key Behaviors to Match

Storing multiple concurrent verifiers (not a single overwritable slot) · A way to identify a specific pending flow when exchanging the code · Bounded storage (evict oldest) to prevent unbounded growth · Falling back to existing single-flow behavior when no flow id is passed (backward compatible)

Acceptance Criteria

  • Feature/fix implemented matching supabase-js behavior
  • Public API follows Dart naming conventions and idioms
  • Unit tests cover happy path and edge cases
  • Documentation updated
  • No breaking changes to existing API (or clearly documented)

Context

  • supabase-js version: v3.0.0-next.29
  • Parity tracking: This issue was auto-generated by SDK parity analysis

Generated with Claude Code /sync-sdk-parity

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions