Skip to content

Simplify OAuth refreshToken middleware by using OAuth service in the middleware#13805

Merged
rickyrombo merged 22 commits intomjp-oauth-net-newfrom
mjp-oauth-standalone
Mar 9, 2026
Merged

Simplify OAuth refreshToken middleware by using OAuth service in the middleware#13805
rickyrombo merged 22 commits intomjp-oauth-net-newfrom
mjp-oauth-standalone

Conversation

@rickyrombo
Copy link
Contributor

Removes the deps on usersApi by removing the isWriteAccessGranted method (which is redundant to the devApps APIs) and the verifyToken method (which is redundant with the usersApi) and calling fetch manually internally.

Then, this allows the OAuth service to be initialized before other APIs so that it can be used in the config for middlewares to all other APIs.

@changeset-bot
Copy link

changeset-bot bot commented Mar 4, 2026

⚠️ No Changeset found

Latest commit: 29a3242

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Copy link
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 refactors the SDK’s OAuth/token-refresh flow to reduce dependencies on generated API clients and to allow OAuth to be instantiated earlier so it can be injected into middleware.

Changes:

  • Remove UsersApi dependency from OAuth (drop isWriteAccessGranted / verifyToken) and perform token verification via direct HTTP request.
  • Simplify addTokenRefreshMiddleware to delegate refresh behavior to OAuth.refreshAccessToken() and retry with the refreshed access token.
  • Initialize OAuth earlier in createSdkWithoutServices and update middleware unit tests to mock OAuth rather than fetch.

Reviewed changes

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

Show a summary per file
File Description
packages/sdk/src/sdk/oauth/OAuth.ts Removes UsersApi coupling; implements manual token verification and changes refresh API to return the new access token.
packages/sdk/src/sdk/middleware/addTokenRefreshMiddleware.ts Switches refresh logic from inline fetch/validation to calling oauth.refreshAccessToken().
packages/sdk/src/sdk/middleware/addTokenRefreshMiddleware.test.ts Updates tests to mock OAuth.refreshAccessToken() instead of mocking cross-fetch.
packages/sdk/src/sdk/createSdkWithoutServices.ts Instantiates OAuth earlier and injects it into the token refresh middleware.
packages/sdk/src/sdk/createSdkWithServices.ts Removes usersApi being passed into OAuth (but currently doesn’t supply basePath).

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

dylanjeffers and others added 14 commits March 4, 2026 15:33
Fixes UI for tracks/collections that dont have artwork
Currently when a user comes back from guest account sign up, they enter
a sign up purgatory loop where they can't finish their account
- `publishTracks` returns string track IDs, which were being incorrectly
parsed as though they were numbers that needed converting. This was
changed behavior from recent SDK changes made to match the POST
endpoints as this was working previously
- `createPlaylist` wasn't equipped to handle using a preset `playlistId`
like our client expects, rejecting calls that had `playlistId` already
set in the metadata (which would happen on our creation of playlists
from scratch).
- `createPlaylistInternal` was being passed parsed parameters in the
`createPlaylist` case, and unparsed in the `uploadPlaylist` case, and
used types that made it hard to squeeze both callsites in. This was
resulting in incorrectly setting some IDs to hash IDs (eg in
`playlistContents`) and was uncovered when fixing the playlistId bug
above
- `updatePlaylist` had incorrect schema still referencing `coverArtCid`
instead of `playlistImageSizesMultihash`, blocking any playlist updates
that included an image update

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1. Top nav CTA
If the user is unauthenticated, the button should say “Sign Up.”
If the user is authenticated, the button should say “Launch.”

2. Hero CTA
The main hero CTA should link to /trending (not Sign Up).

3. Bottom CTA
Change the copy from “Get Started” to “Start Exploring.”
Link this button to /explore.
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @audius/sdk@14.0.0

### Major Changes

- d864806: Remove getPlaylistByHandleAndSlug in favor of
getBulkPlaylists

- Removes `sdk.playlists.getPlaylistByHandleAndSlug()` in favor of
calling `sdk.playlists.getBulkPlaylists({ permalink:
['/handle/playlist/playlist-name-slug'] })`
- Changes return values of `CommentsAPI` to match other APIs, removing
`success` param.

### Minor Changes

-   71bb31b: Add programmable distribution config to stream_conditions

### Patch Changes

-   71bb31b: Fix missing bearer token for PUT /users

-   a7a9e17: Fix create/upload/update playlist in legacy path

- `publishTracks` returns string track IDs, which were being incorrectly
parsed as though they were numbers that needed converting. This was
changed behavior from recent SDK changes made to match the POST
endpoints as this was working previously
- `createPlaylist` wasn't equipped to handle using a preset `playlistId`
like our client expects, rejecting calls that had `playlistId` already
set in the metadata (which would happen on our creation of playlists
from scratch).
- `createPlaylistInternal` was being passed parsed parameters in the
`createPlaylist` case, and unparsed in the `uploadPlaylist` case, and
used types that made it hard to squeeze both callsites in. This was
resulting in incorrectly setting some IDs to hash IDs (eg in
`playlistContents`) and was uncovered when fixing the playlistId bug
above
- `updatePlaylist` had incorrect schema still referencing `coverArtCid`
instead of `playlistImageSizesMultihash`, blocking any playlist updates
that included an image update

- 8f12bb7: Fix cover art CID metadata properties for playlists and
tracks.

-   6cb4b6f: Fix UploadsApi to make start() a function

## @audius/sdk-legacy@6.0.21

### Patch Changes

-   Updated dependencies [71bb31b]
-   Updated dependencies [71bb31b]
-   Updated dependencies [a7a9e17]
-   Updated dependencies [d864806]
-   Updated dependencies [8f12bb7]
-   Updated dependencies [6cb4b6f]
    -   @audius/sdk@14.0.0

## @audius/sp-actions@1.0.25

### Patch Changes

-   @audius/sdk-legacy@6.0.21

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
… entity manager (at least for now) and add support to services-based init + oauth
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Mar 9, 2026

@rickyrombo I've opened a new pull request, #13857, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Mar 9, 2026

@rickyrombo I've opened a new pull request, #13858, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 5 commits March 9, 2026 11:38
The refresh-token exchange logic was moved into
`OAuth.refreshAccessToken()` without corresponding unit tests. This adds
focused coverage for that method.

## Tests added (`OAuth.test.ts`)

- **Success path** — token store is updated with new access + refresh
tokens; new access token is returned
- **Request shape** — verifies `grant_type`, `refresh_token`, and
`client_id` are sent correctly
- **Failure paths**:
  - Non-OK HTTP response → `null`, token store unchanged
  - Invalid JSON body → `null`
  - Missing `access_token` or `refresh_token` in response → `null`
  - Missing `tokenStore` or `basePath` config → `null`
  - No refresh token in store → `null`
  - `fetch` throws (network error) → `null`

`jsdom` is not installed in this package, so the browser-only
constructor guard is satisfied by stubbing `window` via `vi.stubGlobal`.

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rickyrombo <3690498+rickyrombo@users.noreply.github.com>
`addTokenRefreshMiddleware` was calling `oauth.refreshAccessToken()` on
every 401, including unauthenticated requests, causing
`_surfaceError('No refresh token available.')` to fire as noise on
normal 401 responses.

## Changes

- **`OAuth.hasRefreshToken` getter** — cheap boolean check on
`tokenStore?.refreshToken`
- **Middleware guard** — short-circuits on 401 before attempting refresh
when `hasRefreshToken` is false, avoiding the noisy error callback
entirely
- **Test coverage** — asserts `refreshAccessToken` is never called when
`hasRefreshToken` is false

```ts
// Before: refreshAccessToken() called on every 401 → _surfaceError fired for unauthenticated clients
// After: guard skips refresh entirely when no token is stored
if (!oauth.hasRefreshToken) {
  return context.response
}
```

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rickyrombo <3690498+rickyrombo@users.noreply.github.com>
@rickyrombo rickyrombo merged commit 8a8dd59 into mjp-oauth-net-new Mar 9, 2026
4 checks passed
@rickyrombo rickyrombo deleted the mjp-oauth-standalone branch March 9, 2026 18:58
rickyrombo added a commit that referenced this pull request Mar 9, 2026
…middleware (#13805)

Removes the deps on usersApi by removing the `isWriteAccessGranted`
method (which is redundant to the devApps APIs) and the `verifyToken`
method (which is redundant with the usersApi) and calling fetch manually
internally.

Then, this allows the OAuth service to be initialized before other APIs
so that it can be used in the config for middlewares to all other APIs.

---------

Co-authored-by: Dylan Jeffers <dylan@audius.co>
Co-authored-by: Ray Jacobson <ray@audius.co>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
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.

5 participants