Skip to content

fix(oauth-server): prevent authorization code replay race#2617

Open
Kundan-Krishna366 wants to merge 2 commits into
supabase:masterfrom
Kundan-Krishna366:fix/oauth-authorization-code-replay
Open

fix(oauth-server): prevent authorization code replay race#2617
Kundan-Krishna366 wants to merge 2 commits into
supabase:masterfrom
Kundan-Krishna366:fix/oauth-authorization-code-replay

Conversation

@Kundan-Krishna366

Copy link
Copy Markdown

What kind of change does this PR introduce?

Bug fix.

What is the current behavior?

Fixes #2613.

The authorization_code grant flow at POST /oauth/token was vulnerable to a replay race condition. The authorization was loaded and validated before the transaction that issued tokens and destroyed the authorization, allowing concurrent requests to redeem the same authorization code before it was consumed. This could result in multiple successful token exchanges for a single-use authorization code, violating RFC 6749 §4.1.2.

What is the new behavior?

This PR makes authorization code redemption atomic by:

  • Starting the database transaction before loading the authorization.
  • Locking the authorization row during lookup using FOR UPDATE SKIP LOCKED.
  • Performing all authorization validation (expiry, client, redirect URI, resource, PKCE, and user lookup) while holding the row lock.
  • Keeping token issuance and authorization destruction within the same transaction.
  • Preserving *apierrors.OAuthError so concurrent or already-consumed authorization codes correctly return 400 invalid_grant instead of 500 Internal Server Error.

Additionally, this PR adds a regression test that:

  • Creates a valid PKCE authorization code.
  • Launches multiple concurrent POST /oauth/token requests using the same authorization code.
  • Verifies that exactly one request succeeds.
  • Verifies that all remaining requests return 400 invalid_grant.

Additional context

The implementation follows the existing repository locking pattern by extending the existing authorization lookup with a forUpdate mode instead of introducing a new exported helper.

The regression test reproduces the replay scenario described in #2613 and verifies that authorization codes remain single-use under concurrent redemption.

@Kundan-Krishna366 Kundan-Krishna366 requested a review from a team as a code owner July 4, 2026 05:52
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.

Authorization-code replay race (TOCTOU) in the authorization_code grant at POST /oauth/token

1 participant