LibreChat/api/server/routes/admin
Danny Avila fa4a43da21
🔐 fix: Strip code_challenge from Admin OAuth requests before Passport (#12534)
* 🔐 fix: Strip code_challenge from admin OAuth requests before Passport

openid-client v6's Passport Strategy uses `currentUrl.searchParams.size === 0`
to distinguish initial authorization requests from OAuth callbacks. The
admin-panel-specific `code_challenge` query parameter caused the strategy to
misclassify the request as a callback and return 401 Unauthorized.

* 🔐 fix: Strip code_challenge from admin OAuth requests before Passport

openid-client v6's Passport Strategy uses `currentUrl.searchParams.size === 0`
to distinguish initial authorization requests from OAuth callbacks. The
admin-panel-specific `code_challenge` query parameter caused the strategy to
misclassify the request as a callback and return 401 Unauthorized.

- Fix regex to handle `code_challenge` in any query position without producing
  malformed URLs, and handle empty `code_challenge=` values (`[^&]*` vs `[^&]+`)
- Combine `storePkceChallenge` + `stripCodeChallenge` into a single
  `storeAndStripChallenge` helper to enforce read-store-strip ordering
- Apply defensively to all 7 admin OAuth providers
- Add 12 unit tests covering stripCodeChallenge and storeAndStripChallenge

* refactor: Extract PKCE helpers to utility file, harden tests

- Move stripCodeChallenge and storeAndStripChallenge to
  api/server/utils/adminPkce.js — eliminates _test production export
  and avoids loading the full auth.js module tree in tests
- Add missing req.originalUrl/req.url assertions to invalid-challenge
  and no-challenge test branches (regression blind spots)
- Hoist cache reference to module scope in tests (was redundantly
  re-acquired from mock factory on every beforeEach)

* chore: Address review NITs — imports, exports, naming, assertions

- Fix import order in auth.js (longest-to-shortest per CLAUDE.md)
- Remove unused PKCE_CHALLENGE_TTL/PKCE_CHALLENGE_PATTERN exports
- Hoist strip arrow to module-scope stripChallengeFromUrl
- Rename auth.test.js → auth.spec.js (project convention)
- Tighten cache-failure test: toBe instead of toContain, add req.url

* refactor: Move PKCE helpers to packages/api with dependency injection

Move stripCodeChallenge and storeAndStripChallenge from api/server/utils
into packages/api/src/auth/exchange.ts alongside the existing PKCE
verification logic. Cache is now injected as a Keyv parameter, matching
the dependency-injection pattern used throughout packages/api/.

- Add PkceStrippableRequest interface for minimal req typing
- auth.js imports storeAndStripChallenge from @librechat/api
- Delete api/server/utils/adminPkce.js
- Move tests to packages/api/src/auth/adminPkce.spec.ts (TypeScript,
  real Keyv instances, no getLogStores mock needed)
2026-04-02 21:03:44 -04:00
..
auth.js 🔐 fix: Strip code_challenge from Admin OAuth requests before Passport (#12534) 2026-04-02 21:03:44 -04:00
config.js 🧵 feat: ALS Context Middleware, Tenant Threading, and Config Cache Invalidation (#12407) 2026-03-26 17:35:00 -04:00
grants.js ⛩️ feat: Admin Grants API Endpoints (#12438) 2026-03-30 16:49:23 -04:00
groups.js 🛡️ fix: Restrict System Grants to Role Principals (#12491) 2026-03-31 19:25:14 -04:00
roles.js ⛩️ feat: Admin Grants API Endpoints (#12438) 2026-03-30 16:49:23 -04:00
users.js 🛡️ fix: Restrict System Grants to Role Principals (#12491) 2026-03-31 19:25:14 -04:00