Skip to content

Promisify OAuth service login#13892

Merged
rickyrombo merged 12 commits into
mainfrom
mjp-oauth-env-promise
Mar 11, 2026
Merged

Promisify OAuth service login#13892
rickyrombo merged 12 commits into
mainfrom
mjp-oauth-env-promise

Conversation

@rickyrombo
Copy link
Copy Markdown
Contributor

Updates OAuth service loginAsync() to be promise-based. Keeps login() the same. Removes need for init() to be called.

Also removes some unused types. Updates the OAUTH_URL to be instead the API url from the config now that it redirects, which allows for handling multiple environments. However, since it redirects, removed the origin check on the postmessage since it won't come from the API server url.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 11, 2026

🦋 Changeset detected

Latest commit: 51c3bad

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

This PR includes changesets to release 3 packages
Name Type
@audius/sdk Patch
@audius/sdk-legacy 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 updates the SDK’s OAuth module to support a promise-based loginAsync() flow, reduces reliance on init(), and switches the authorization URL to be derived from the configured API basePath (rather than a hardcoded production OAuth URL).

Changes:

  • Adds a loginAsync() API that returns a Promise<LoginResult> and refactors login() to delegate to it.
  • Removes hardcoded OAuth environment/url constants and some previously exported types.
  • Updates popup postMessage handling to accommodate redirects (origin check removed) and consolidates promise settlement via _settleLogin().

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 10 comments.

File Description
packages/sdk/src/sdk/oauth/types.ts Removes previously exported OAuth URL/env + unused schema/types; adds LoginResult.
packages/sdk/src/sdk/oauth/OAuth.ts Implements promise-based login flow, moves message listener into constructor, updates auth URL construction and message handling.
.changeset/tricky-zoos-film.md Declares a patch release for the OAuth changes.

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

Comment thread .changeset/tricky-zoos-film.md
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts Outdated
Comment thread packages/sdk/src/sdk/oauth/types.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts
Comment thread packages/sdk/src/sdk/oauth/OAuth.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 11, 2026

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

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 11, 2026

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

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 11, 2026

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

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 11, 2026

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

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 11, 2026

🌐 Web preview ready

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

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

Copilot AI and others added 6 commits March 11, 2026 14:37
`loginAsync()` stored resolve/reject in instance fields, so a second
concurrent call would overwrite those handlers, leaving the first
promise permanently unresolved.

## Changes

- **`OAuth.ts`**: Added an early-reject guard at the top of
`loginAsync()` — if `_currentLoginResolve` is already set (login
in-flight), the new call immediately rejects rather than clobbering the
existing handlers.

```ts
if (this._currentLoginResolve != null) {
  return Promise.reject(new Error('A login is already in progress.'))
}
```

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

✨ Let Copilot coding agent [set things up for
you](https://github.com/AudiusProject/apps/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rickyrombo <3690498+rickyrombo@users.noreply.github.com>
When `window.open()` is blocked by the browser it returns `null`,
leaving the login promise permanently unresolved since no message event
or close-check can ever fire.

## Changes

- **Popup blocked detection**: Check the return value of `window.open()`
immediately after the call
- **Immediate rejection**: Reject the login promise with an actionable
error when the popup is blocked, instead of hanging indefinitely
- **Early return**: Skip setting up the close-check interval when
there's no window to monitor

```ts
this.activePopupWindow = window.open(fullOauthUrl, '', windowOptions)
if (!this.activePopupWindow) {
  this._settleLogin(
    new Error(
      'The login popup was blocked. Please allow popups for this site and try again.'
    )
  )
  return promise
}
```

<!-- 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>
`basePath` is optional in `OAuthConfig`, but the PKCE `{state, code}`
handler in `_receiveMessage` unconditionally used it when fetching
`/oauth/token` and `/oauth/me`, resulting in fetches to
`undefined/oauth/token` with no meaningful error surfaced to the caller.

## Changes

- **`packages/sdk/src/sdk/oauth/OAuth.ts`**: Added an early-exit guard
in the PKCE branch that rejects via `_settleLogin` with a descriptive
error if `basePath` is not configured, before any fetch is attempted.

```ts
if (!this.config.basePath) {
  this._settleLogin(
    new Error(
      'basePath is required in SDK configuration for PKCE token exchange.'
    )
  )
  return
}
```

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

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rickyrombo <3690498+rickyrombo@users.noreply.github.com>
Each `OAuth` instance attached a `window.addEventListener('message',
...)` in its constructor and never removed it, causing listener
accumulation across multiple SDK instantiations and risking duplicate
message processing.

## Changes

- **Removed constructor listener** — `window.addEventListener` no longer
called at construction time
- **Lazy registration in `loginAsync`** — listener is attached only when
entering the `postMessage` popup flow; guarded against
double-registration if `loginAsync` is called again while a login is in
progress
- **Cleanup in `_settleLogin`** — listener is removed (and popup check
interval cleared) as soon as the login resolves or rejects, via a stored
`_boundMessageHandler` reference

```ts
// Before: listener lived forever, one per OAuth instance
constructor(...) {
  window.addEventListener('message', (e) => this._receiveMessage(e), false)
}

// After: listener scoped to each login attempt
async loginAsync({ redirectUri = 'postMessage', ... }) {
  if (redirectUri === 'postMessage' && !this._boundMessageHandler) {
    this._boundMessageHandler = (e) => this._receiveMessage(e)
    window.addEventListener('message', this._boundMessageHandler, false)
  }
  // ...
}

private _settleLogin(resultOrError) {
  // resolve/reject promise...
  window.removeEventListener('message', this._boundMessageHandler, false)
  this._boundMessageHandler = null
  this._clearPopupCheckInterval()
}
```

- **Tests** — added `removeEventListener` + `crypto.getRandomValues` to
the window stub; new `OAuth message listener lifecycle` suite covering:
no listener on construction, listener attached on `loginAsync`, no
duplicate on re-entry, listener removed on settle

<!-- 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>
@rickyrombo rickyrombo merged commit 0bfa30f into main Mar 11, 2026
5 checks passed
@rickyrombo rickyrombo deleted the mjp-oauth-env-promise branch March 11, 2026 22:13
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.

4 participants