Skip to content

Fix OAuth token exchange duplicate key error on request_id - #8

Merged
demdxx merged 1 commit into
mainfrom
cursor/fix-oauth-token-exchange-duplicate-b73b
Sep 18, 2026
Merged

demdxx merged 1 commit into
mainfrom
cursor/fix-oauth-token-exchange-duplicate-b73b

Conversation

@demdxx

@demdxx demdxx commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Problem

OAuth token exchange was failing in production with:

ERROR: duplicate key value violates unique constraint "idx_auth_session_uniq_request_id" (SQLSTATE 23505)

This occurred during the authorization_code grant flow when CreateAccessTokenSession tried to INSERT a new auth_session row with the same request_id that was already created by CreateAuthorizeCodeSession.

Production Context

Root Cause

Fosite reuses the same request.GetID() across the OAuth flow lifecycle:

  1. CreateAuthorizeCodeSession: Creates session with request_id=req-123, access_token=auth-code
  2. CreatePKCERequestSession: Updates that session with PKCE data (PR Fix PKCE auth_session duplicate key error (SQLSTATE 23505) #6 fix)
  3. CreateAccessTokenSession: Tried to INSERT new session with request_id=req-123 (same!), access_token=new-token → UNIQUE constraint violation

The issue is that CreateAccessTokenSession was always INSERTing instead of UPDATing the existing session.

Solution

Changed CreateAccessTokenSession to follow the same pattern as CreatePKCERequestSession:

  1. Look up existing session by request_id
  2. If found, UPDATE it with the new access token signature and session data
  3. Only INSERT if no existing session is found (edge case fallback)

This correctly models the OAuth flow: a single session row that evolves through the authorize → token exchange lifecycle.

Changes

storage.go

  • Rewrote CreateAccessTokenSession to UPDATE existing sessions by request_id
  • Preserves UNIQUE constraints on both request_id and access_token (where deleted_at IS NULL)
  • Added detailed comments explaining the fosite reuse behavior

storage_test.go

  • Added TestAuthorizationCodeToAccessTokenFlow to verify the full flow
  • Tests: CreateAuthorizeCodeSession → CreateAccessTokenSession correctly updates (no duplicate INSERT)

Testing

✅ All existing tests pass
✅ New test covers authorization_code → access_token exchange
✅ Preserves behavior from PR #6 (CreatePKCERequestSession)

Next Steps for Affyard

After this PR merges, bump the blaze-api submodule in the Affyard repository to pick up this fix.

Open in Web Open in Cursor 

During authorization_code grant flow, CreateAccessTokenSession was
INSERTing a new row with the same request_id from the authorize step,
violating the UNIQUE constraint idx_auth_session_uniq_request_id.

Root cause: Fosite reuses the same request.GetID() across the authorize
and token exchange steps, so both CreateAuthorizeCodeSession and
CreateAccessTokenSession were trying to create separate rows with the
same request_id.

Fix: CreateAccessTokenSession now:
1. Looks up the existing session by request_id (from authorize step)
2. Updates it with the new access token signature and session data
3. Only INSERTs if no existing session is found (edge case)

This matches the approach used in CreatePKCERequestSession (PR #6) and
aligns with how fosite manages OAuth sessions - a single session row
evolves through the authorize → token exchange lifecycle.

Added TestAuthorizationCodeToAccessTokenFlow to verify the full flow:
CreateAuthorizeCodeSession → CreateAccessTokenSession correctly updates
the existing session instead of creating a duplicate.

Co-authored-by: Dmitry <demdxx@gmail.com>
@demdxx
demdxx marked this pull request as ready for review September 18, 2026 15:27
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 35361913195

Coverage increased (+0.1%) to 4.061%

Details

  • Coverage increased (+0.1%) from the base build.
  • Patch coverage: 9 uncovered changes across 1 file (39 of 48 lines covered, 81.25%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
pkg/auth/oauth2/serverprovider/storage.go 48 39 81.25%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 27482
Covered Lines: 1116
Line Coverage: 4.06%
Coverage Strength: 0.04 hits per line

💛 - Coveralls

@demdxx
demdxx merged commit 181bcfc into main Sep 18, 2026
6 checks passed
@demdxx
demdxx deleted the cursor/fix-oauth-token-exchange-duplicate-b73b branch September 18, 2026 15:43
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.

3 participants