LibreChat/packages/api
Oreon Lothamer eb6328c1d9
🛤️ fix: Base URL Fallback for Path-based OAuth Discovery in Token Refresh (#12164)
* fix: add base URL fallback for path-based OAuth discovery in token refresh

The two `refreshOAuthTokens` paths in `MCPOAuthHandler` were missing the
origin-URL fallback that `initiateOAuthFlow` already had. With MCP SDK
1.27.1, `buildDiscoveryUrls` appends the server path to the
`.well-known` URL (e.g. `/.well-known/oauth-authorization-server/mcp`),
which returns 404 for servers like Sentry that only expose the root
discovery endpoint (`/.well-known/oauth-authorization-server`).

Without the fallback, discovery returns null during refresh, the token
endpoint resolves to the wrong URL, and users are prompted to
re-authenticate every time their access token expires instead of the
refresh token being exchanged silently.

Both refresh paths now mirror the `initiateOAuthFlow` pattern: if
discovery fails and the server URL has a non-root path, retry with just
the origin URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: extract discoverWithOriginFallback helper; add tests

Extract the duplicated path-based URL retry logic from both
`refreshOAuthTokens` branches into a single private static helper
`discoverWithOriginFallback`, reducing the risk of the two paths
drifting in the future.

Add three tests covering the new behaviour:
- stored clientInfo path: asserts discovery is called twice (path then
  origin) and that the token endpoint from the origin discovery is used
- auto-discovered path: same assertions for the branchless path
- root URL: asserts discovery is called only once when the server URL
  already has no path component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: use discoverWithOriginFallback in discoverMetadata too

Remove the inline duplicate of the origin-fallback logic from
`discoverMetadata` and replace it with a call to the shared
`discoverWithOriginFallback` helper, giving all three discovery
sites a single implementation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: use mock.calls + .href/.toString() for URL assertions

Replace brittle `toHaveBeenNthCalledWith(new URL(...))` comparisons
with `expect.any(URL)` matchers and explicit `.href`/`.toString()`
checks on the captured call args, consistent with the existing
mock.calls pattern used throughout handler.test.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 15:04:35 -04:00
..
src 🛤️ fix: Base URL Fallback for Path-based OAuth Discovery in Token Refresh (#12164) 2026-03-10 15:04:35 -04:00
.gitignore 🧠 feat: User Memories for Conversational Context (#7760) 2025-06-07 18:52:22 -04:00
babel.config.cjs 🧠 feat: User Memories for Conversational Context (#7760) 2025-06-07 18:52:22 -04:00
jest.config.mjs refactor: Parallelize CI Workflows with Isolated Caching and Fan-Out Test Jobs (#12088) 2026-03-05 13:56:07 -05:00
package.json v0.8.3 (#12161) 2026-03-09 15:19:57 -04:00
rollup.config.js 🔄 refactor: Migrate Cache Logic to TypeScript (#9771) 2025-10-02 09:33:58 -04:00
tsconfig-paths-bootstrap.mjs 🧠 feat: User Memories for Conversational Context (#7760) 2025-06-07 18:52:22 -04:00
tsconfig.build.json 🧑‍💻 refactor: Secure Field Selection for 2FA & API Build Sourcemap (#9087) 2025-08-15 18:55:49 -04:00
tsconfig.json 🌊 feat: Resumable LLM Streams with Horizontal Scaling (#10926) 2025-12-19 12:14:19 -05:00
tsconfig.spec.json 🧠 feat: User Memories for Conversational Context (#7760) 2025-06-07 18:52:22 -04:00