Skip to content

feat(oauth): show credential age and keep provider status current - #943

Merged
mcowger merged 2 commits into
mcowger:mainfrom
darkspadez:test/meta-oauth-identity
Sep 25, 2026
Merged

mcowger merged 2 commits into
mcowger:mainfrom
darkspadez:test/meta-oauth-identity

Conversation

@darkspadez

Copy link
Copy Markdown
Collaborator

Overview

OAuth provider settings now show when an account was connected, when its key was last refreshed, and when it expires. The status updates while the provider form stays open, and completed logins appear only after their credentials are saved.

✨ New Features

  • Credential age in provider settings: See connection, refresh, and expiration timing, with exact dates on hover.

🐛 Bug Fixes

  • OAuth logins now report success only after credentials are saved; failed saves and cancellation during saving no longer leave a misleading connected status.
  • Connecting or removing an OAuth account refreshes provider configuration so linked providers update without a restart.

🔧 Improvements

  • Open provider forms refresh credential status every 10 seconds and retain the last known status during a temporary request failure.

Verification

  • bun run test — 122 files, 1,017 tests passed
  • bun run typecheck
  • bun run lint:check
  • bun run format:check
  • Provider form rendering and status refresh verified in a browser

darkspadez and others added 2 commits September 25, 2026 15:34
- The credential status endpoint and provider form show when the login
  was connected, last refreshed and when the key expires.
- Saving a new OAuth credential (or backfill-linking a provider) and
  deleting one now rebuild the config cache, so runtime oauth_account
  hydration no longer goes stale until a restart or provider re-save.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 1 issue(s) in this PR.

  • ✅ Successfully posted inline: 1 comment(s)

Comment on lines +336 to +339
const result = await api.getOAuthCredentialStatus(providerId, accountId);
if (cancelled) return;
setOauthCredentialReady(!!result.ready);
setOauthCredentialStatus(result.ready ? result : null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

bug · medium
Race with delete: the new 10s poll can be in flight while handleDeleteOAuthCredential runs. When there's no active session, oauthStatus stays undefined, so the delete doesn't change any effect dependency and the effect never cancels. If a poll that started before the delete resolves after it, it sets ready: true and the old credential status again. The credential line and Delete button then come back for up to 10s after a successful delete. Before this change the check ran only once, so this couldn't happen. Fix: keep a request/generation counter in a ref, bump it in the delete handler, and drop any poll result whose generation is stale (or add a credentialVersion state to the effect deps and bump it on delete).

Suggestion:

Suggested change
const result = await api.getOAuthCredentialStatus(providerId, accountId);
if (cancelled) return;
setOauthCredentialReady(!!result.ready);
setOauthCredentialStatus(result.ready ? result : null);
const gen = credentialGenRef.current;
const result = await api.getOAuthCredentialStatus(providerId, accountId);
if (cancelled || gen !== credentialGenRef.current) return;
setOauthCredentialReady(!!result.ready);
setOauthCredentialStatus(result.ready ? result : null);

@github-actions

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview — detailed findings

✅ Passing — no critical/high findings.

Reviewed 14 file(s), 1 finding(s) total.

  • medium — packages/frontend/src/hooks/useProviderForm.tsx:336-339: Race with delete: the new 10s poll can be in flight while handleDeleteOAuthCredential runs. When there's no active session, oauthStatus stays undefined, so the delete doesn't change any effect dependency and the effect never cancels. If a poll that started before the delete resolves after it, it sets ready: true and the old credential status again. The credential line and Delete button then come back for up to 10s after a successful delete. Before this change the check ran only once, so this couldn't happen. Fix: keep a request/generation counter in a ref, bump it in the delete handler, and drop any poll result whose generation is stale (or add a credentialVersion state to the effect deps and bump it on delete).

    Suggested change
            const gen = credentialGenRef.current;
          const result = await api.getOAuthCredentialStatus(providerId, accountId);
          if (cancelled || gen !== credentialGenRef.current) return;
          setOauthCredentialReady(!!result.ready);
          setOauthCredentialStatus(result.ready ? result : null);
    

@mcowger
mcowger merged commit 7ce67ae into mcowger:main Sep 25, 2026
4 checks passed
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.

2 participants