Skip to content

fix(sdk): NaN-safe expiry parsing + AsyncStorage token store tests#14078

Open
rickyrombo wants to merge 3 commits intomainfrom
mjp-oauth-token-expiry-tracking
Open

fix(sdk): NaN-safe expiry parsing + AsyncStorage token store tests#14078
rickyrombo wants to merge 3 commits intomainfrom
mjp-oauth-token-expiry-tracking

Conversation

@rickyrombo
Copy link
Copy Markdown
Contributor

@rickyrombo rickyrombo commented Apr 8, 2026

getAccessTokenExpiry() / getRefreshTokenExpiry() returned NaN when localStorage or AsyncStorage held a non-numeric value (corruption, manual edits, format migration). NaN silently bypasses expiry checks since Date.now() >= NaN is always false, meaning expired sessions could be treated as valid.

Changes

  • NaN safety (TokenStoreLocalStorage, TokenStoreAsyncStorage): replace bare Number(raw) with Number.isFinite() guard — invalid stored values return null instead of NaN
  • Tests (tokenStoreAsyncStorage.test.ts): new test file mocking @react-native-async-storage/async-storage, covering token reads, expiry persistence, removal of expiry keys when not provided, NaN/corruption handling, and clear
// Before — NaN slips through
const raw = await AsyncStorage.getItem(key)
return raw ? Number(raw) : null  // returns NaN for "corrupted-value"

// After — invalid values treated as absent
const n = Number(raw)
return Number.isFinite(n) ? n : null

- Add getAccessTokenExpiry/getRefreshTokenExpiry to OAuthTokenStore interface
- Track expiry in all three store implementations (Memory, LocalStorage, AsyncStorage)
- isAuthenticated() now checks token expiry and attempts silent refresh
- getUser() retries once with refreshed token on 401 instead of throwing
- Pass expires_in and refresh_expires_in from server to token stores

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: cd7e1fe

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@audius/sdk Minor
@audius/sdk-legacy Patch
@audius/protocol-dashboard Patch
@audius/sp-actions Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Contributor

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

This PR enhances the SDK OAuth session handling by persisting token expiry timestamps in token stores and using that information to proactively refresh/validate sessions, plus adding a single retry in getUser() after a token refresh on 401.

Changes:

  • Extend OAuthTokenStore to track access/refresh token expiries and persist them (Memory, LocalStorage, AsyncStorage).
  • Update OAuth.isAuthenticated() to consider expiry (including silent refresh) and update getUser() to retry once on 401 after refresh.
  • Expand/adjust unit tests for the new expiry/refresh behavior and add a changeset entry.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/sdk/src/sdk/oauth/tokenStore.ts Expands the public token store interface with expiry getters and optional expiry params in setTokens().
packages/sdk/src/sdk/oauth/TokenStoreMemory.ts Stores expiry timestamps in-memory and clears them with tokens.
packages/sdk/src/sdk/oauth/TokenStoreLocalStorage.ts Persists expiry timestamps to localStorage alongside tokens.
packages/sdk/src/sdk/oauth/tokenStoreLocalStorage.test.ts Adds tests for expiry key persistence/removal/reading in localStorage store.
packages/sdk/src/sdk/oauth/TokenStoreAsyncStorage.ts Persists expiry timestamps to AsyncStorage alongside tokens.
packages/sdk/src/sdk/oauth/tokenStore.test.ts Updates memory-store tests to include expiry behavior.
packages/sdk/src/sdk/oauth/OAuth.ts Implements expiry-aware isAuthenticated(), adds getUser() 401 refresh+retry, and persists token expiries from token responses.
packages/sdk/src/sdk/oauth/OAuth.test.ts Adds/updates tests for expiry-aware authentication and getUser() retry behavior.
.changeset/oauth-token-expiry-tracking.md Declares a release bump and describes the OAuth reliability improvements.

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

🌐 Web preview ready

Preview URL: https://audius-web-preview-pr-14078.audius.workers.dev

Unique preview for this PR (deployed from this branch).
Workflow run

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
rickyrombo added a commit to AudiusProject/api that referenced this pull request Apr 8, 2026
## Summary
- Adds `refresh_expires_in` field (30 days in seconds) to both the
authorization code exchange and refresh token grant responses
- Companion to AudiusProject/apps#14078 which adds client-side token
expiry tracking to the SDK

## Test plan
- [ ] `POST /v1/oauth/token` (authorization_code grant) response
includes `refresh_expires_in: 2592000`
- [ ] `POST /v1/oauth/token` (refresh_token grant) response includes
`refresh_expires_in: 2592000`
- [ ] Existing `expires_in` field unchanged (still 3600)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
… expiry getters

Agent-Logs-Url: https://github.com/AudiusProject/apps/sessions/0d8ac21d-1301-49dd-af18-338163d60570

Co-authored-by: rickyrombo <3690498+rickyrombo@users.noreply.github.com>
@pull-request-size pull-request-size bot added size/XL and removed size/L labels Apr 8, 2026
Copilot AI changed the title fix(sdk): Add token expiry tracking and retry logic to OAuth fix(sdk): NaN-safe expiry parsing + AsyncStorage token store tests Apr 8, 2026
@rickyrombo rickyrombo requested a review from dylanjeffers April 8, 2026 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants