Skip to content

Fix auth token refresh by passing client credentials#254

Merged
jeremy merged 2 commits intomainfrom
fix/auth-refresh-client-id
Mar 11, 2026
Merged

Fix auth token refresh by passing client credentials#254
jeremy merged 2 commits intomainfrom
fix/auth-refresh-client-id

Conversation

@jeremy
Copy link
Copy Markdown
Member

@jeremy jeremy commented Mar 11, 2026

Summary

  • refreshLocked was sending RefreshRequest without ClientID/ClientSecret, causing "Missing client_id" errors from the token endpoint
  • Resolves client credentials per OAuthType: BC3 loads from client.json, Launchpad uses env vars or built-in defaults
  • Migrates old credentials: empty OAuthType defaults to "launchpad", empty TokenEndpoint is derived for launchpad (hard error for bc3)
  • Clears ExpiresAt to 0 when server omits expires_in, preserving the existing contract (ExpiresAt==0 means non-expiring at auth.go:93)
  • Surfaces the BC3 custom-redirect limitation explicitly: DCR credentials from custom-redirect logins are intentionally session-only (not persisted per auth.go:659), so refresh after restart fails with a clear diagnostic rather than a generic error

Scope limitation

Default-redirect BC3 refresh is fixed. Custom-redirect BC3 refresh after process restart remains unsupported because DCR credentials are intentionally not persisted (they'd become stale without the redirect override). The error message now explains this clearly.

Test plan

  • Auth token expiry with Launchpad → refresh succeeds (sends client_id) — TestRefreshLocked_LaunchpadSendsClientID
  • Auth token expiry with BC3 (default redirect) → refresh succeeds — TestRefreshLocked_BC3SendsClientID
  • Auth token expiry with BC3 (custom redirect, after restart) → clear error — TestRefreshLocked_BC3WithoutClientJSON
  • Old credentials without OAuthType → refresh works (defaults to launchpad) — TestRefreshLocked_EmptyOAuthTypeDefaultsToLaunchpad
  • Server omits expires_in → ExpiresAt cleared to 0 (no re-trigger loop) — TestRefreshLocked_ClearsExpiresAtWhenServerOmits
  • bin/ci passes
  • New unit tests: TestRefreshLocked_* (5 tests, all pass with -race)

refreshLocked was sending RefreshRequest without ClientID/ClientSecret,
causing "Missing client_id" errors from the token endpoint.

- Resolve client credentials per OAuthType: BC3 loads from client.json,
  Launchpad uses env vars or built-in defaults
- Migrate old credentials: empty OAuthType defaults to "launchpad",
  empty TokenEndpoint is derived for launchpad (hard error for bc3)
- Clear ExpiresAt to 0 when server omits expires_in, preserving the
  existing contract (ExpiresAt==0 means non-expiring)
- Surface the BC3 custom-redirect limitation: DCR credentials from
  custom-redirect logins are session-only and not persisted, so refresh
  after process restart fails with a clear diagnostic
@jeremy jeremy requested a review from a team as a code owner March 11, 2026 03:37
Copilot AI review requested due to automatic review settings March 11, 2026 03:37
@github-actions github-actions bot added tests Tests (unit and e2e) auth OAuth authentication labels Mar 11, 2026
@github-actions github-actions bot added the bug Something isn't working label Mar 11, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes OAuth token refresh failures by ensuring refresh requests include client credentials, with provider-aware credential resolution and migrations for older stored credential formats.

Changes:

  • Update refreshLocked to migrate missing OAuthType/TokenEndpoint and include ClientID/ClientSecret in refresh requests.
  • Improve handling of missing expires_in by clearing ExpiresAt to 0 (non-expiring contract).
  • Add unit tests covering Launchpad/BC3 refresh credential inclusion, migrations, and expiry behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
internal/auth/auth.go Adds credential migrations and provider-specific client credential resolution for refresh requests; adjusts expiry handling.
internal/auth/auth_test.go Adds new TestRefreshLocked_* cases validating refresh request params and expiry/migration behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…nching

- Guard capturedBody with sync.Mutex in 3 refresh tests (race detector)
- Clear BASECAMP_OAUTH_CLIENT_ID/SECRET env vars in launchpad tests
- Branch BC3 client load error on os.IsNotExist for custom-redirect explanation
@jeremy jeremy merged commit 514ac04 into main Mar 11, 2026
26 checks passed
@jeremy jeremy deleted the fix/auth-refresh-client-id branch March 11, 2026 05:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth OAuth authentication bug Something isn't working tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants