Skip to content

fix(auth): make OAuth refresh concurrent-safe and recoverable #4

Description

@zendext

Requirement

Harden Codex OAuth refresh so concurrent expiry and upstream 401 responses do not race refresh-token use, corrupt auth files, or expose internal token-endpoint failures to proxy clients.

Decisions

  • Support both proactive refresh near local expiry and reactive refresh after an upstream 401.
  • Coordinate refresh per stable auth identity with an in-process lock/singleflight.
  • Concurrent callers must reuse a refresh that already replaced the failed access token.
  • After 401, refresh the same auth once and retry that auth once before failover.
  • Refresh has one 30-second overall deadline and at most three total attempts.
  • Retry only transient network failures, 408, 429, and 500/502/503/504; honor Retry-After only within the overall deadline.
  • Do not retry invalid_grant, missing refresh credentials, definitive 400/401/403, malformed responses, or responses without an access token.
  • Persist refreshed auth JSON with a same-directory temporary file, file sync, atomic rename, and 0600 permissions.
  • Reparse refreshed identity tokens and never log or return tokens or raw sensitive refresh responses.

Acceptance Criteria

  • Concurrent requests for one expired auth cause one effective refresh operation; waiters receive the same result.
  • A 401 produced by an old token can reuse another request's completed refresh without calling the token endpoint again.
  • Successful refresh atomically updates access token, rotated refresh token, ID token, expiry, account ID, and email where supplied.
  • A failed save leaves the previous auth file readable and intact.
  • Refresh cancellation and the 30-second deadline stop retries promptly.
  • Client-facing proxy errors are sanitized while debug logs retain safe operational context.
  • Tests cover concurrency, rotated refresh tokens, reactive 401, transient retries, terminal refresh failures, cancellation, and atomic-save failure.

Non-goals

  • Cross-process refresh locking.
  • Moving OAuth credentials into SQLite.
  • Background refresh worker pools.

Dependencies

Verification

  • gofmt -w .
  • go test ./...
  • go build -o test-output ./cmd/server && rm test-output

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions