🔐 feat: Mint Code API Auth Tokens (#13028)

* feat: Mint CodeAPI auth tokens

* style: Format CodeAPI download route

* fix: Prune CodeAPI token cache

* fix: Propagate CodeAPI managed auth

* test: Mock CodeAPI auth in traversal suite

* fix: Pass auth context to invoked skill cache

* feat: Mint CodeAPI plan context

* chore: Refresh CodeAPI auth guidance

* fix: Guard OpenID JWT fallback

* fix: Default CodeAPI JWT tenant in single-tenant mode

* chore: Update @librechat/agents to version 3.1.84 in package-lock.json and package.json files

* chore: Standardize references to Code API in comments and tests
This commit is contained in:
Danny Avila 2026-05-09 16:09:10 -04:00 committed by GitHub
parent 8a654dc8b1
commit c67e2b54dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 973 additions and 58 deletions

View file

@ -13,17 +13,25 @@ const { getTenantId } = require('@librechat/data-schemas');
// ── Mocks ──────────────────────────────────────────────────────────────
let mockPassportError = null;
let mockRegisteredStrategies = new Set(['jwt']);
jest.mock('passport', () => ({
authenticate: jest.fn(() => {
return (req, _res, done) => {
_strategy: jest.fn((strategy) => (mockRegisteredStrategies.has(strategy) ? {} : undefined)),
authenticate: jest.fn((strategy, _options, callback) => {
return (req, _res, _done) => {
if (mockPassportError) {
return done(mockPassportError);
return callback(mockPassportError);
}
if (req._mockUser) {
req.user = req._mockUser;
const strategyResult = req._mockStrategies?.[strategy];
if (strategyResult) {
return callback(
strategyResult.err ?? null,
strategyResult.user ?? false,
strategyResult.info,
strategyResult.status,
);
}
done();
return callback(null, req._mockUser ?? false, { message: 'Unauthorized' }, 401);
};
}),
}));
@ -49,9 +57,11 @@ jest.mock('@librechat/api', () => {
// ── Helpers ─────────────────────────────────────────────────────────────
const requireJwtAuth = require('../requireJwtAuth');
const { isEnabled } = require('@librechat/api');
const passport = require('passport');
function mockReq(user) {
return { headers: {}, _mockUser: user };
function mockReq(user, extra = {}) {
return { headers: {}, _mockUser: user, ...extra };
}
function mockRes() {
@ -74,6 +84,10 @@ function runAuth(user) {
describe('requireJwtAuth tenant context chaining', () => {
afterEach(() => {
mockPassportError = null;
mockRegisteredStrategies = new Set(['jwt']);
isEnabled.mockReturnValue(false);
passport.authenticate.mockClear();
passport._strategy.mockClear();
});
it('forwards passport errors to next() without entering tenant middleware', async () => {
@ -98,9 +112,61 @@ describe('requireJwtAuth tenant context chaining', () => {
expect(tenantId).toBeUndefined();
});
it('ALS tenant context is NOT set when user is undefined', async () => {
const tenantId = await runAuth(undefined);
expect(tenantId).toBeUndefined();
it('returns 401 when no strategy authenticates a user', async () => {
const req = mockReq(undefined);
const res = mockRes();
const next = jest.fn();
requireJwtAuth(req, res, next);
expect(next).not.toHaveBeenCalled();
expect(res.status).toHaveBeenCalledWith(401);
expect(getTenantId()).toBeUndefined();
});
it('falls back to OpenID JWT for bearer-only reuse requests', async () => {
isEnabled.mockReturnValue(true);
mockRegisteredStrategies.add('openidJwt');
const req = mockReq(undefined, {
_mockStrategies: {
jwt: { user: false, info: { message: 'invalid signature' }, status: 401 },
openidJwt: { user: { tenantId: 'tenant-openid', role: 'user' } },
},
});
const res = mockRes();
const tenantId = await new Promise((resolve) => {
requireJwtAuth(req, res, () => {
resolve(getTenantId());
});
});
expect(tenantId).toBe('tenant-openid');
expect(req.authStrategy).toBe('openidJwt');
expect(res.status).not.toHaveBeenCalled();
});
it('skips OpenID JWT fallback when the strategy was not registered', async () => {
isEnabled.mockReturnValue(true);
const req = mockReq(undefined, {
_mockStrategies: {
jwt: { user: false, info: { message: 'invalid signature' }, status: 401 },
openidJwt: { user: { tenantId: 'tenant-openid', role: 'user' } },
},
});
const res = mockRes();
const next = jest.fn();
requireJwtAuth(req, res, next);
expect(next).not.toHaveBeenCalled();
expect(res.status).toHaveBeenCalledWith(401);
expect(req.authStrategy).toBeUndefined();
expect(passport.authenticate).toHaveBeenCalledTimes(1);
expect(passport.authenticate).toHaveBeenCalledWith(
'jwt',
{ session: false },
expect.any(Function),
);
});
it('concurrent requests get isolated tenant contexts', async () => {

View file

@ -2,23 +2,31 @@ const cookies = require('cookie');
const passport = require('passport');
const { isEnabled, tenantContextMiddleware } = require('@librechat/api');
const hasPassportStrategy = (strategy) =>
typeof passport._strategy === 'function' && passport._strategy(strategy) != null;
// This middleware does not require authentication,
// but if the user is authenticated, it will set the user object
// and establish tenant ALS context.
const optionalJwtAuth = (req, res, next) => {
const cookieHeader = req.headers.cookie;
const tokenProvider = cookieHeader ? cookies.parse(cookieHeader).token_provider : null;
const useOpenIdJwt =
tokenProvider === 'openid' &&
isEnabled(process.env.OPENID_REUSE_TOKENS) &&
hasPassportStrategy('openidJwt');
const callback = (err, user) => {
if (err) {
return next(err);
}
if (user) {
req.user = user;
req.authStrategy = useOpenIdJwt ? 'openidJwt' : 'jwt';
return tenantContextMiddleware(req, res, next);
}
next();
};
if (tokenProvider === 'openid' && isEnabled(process.env.OPENID_REUSE_TOKENS)) {
if (useOpenIdJwt) {
return passport.authenticate('openidJwt', { session: false }, callback)(req, res, next);
}
passport.authenticate('jwt', { session: false }, callback)(req, res, next);

View file

@ -2,6 +2,9 @@ const cookies = require('cookie');
const passport = require('passport');
const { isEnabled, tenantContextMiddleware } = require('@librechat/api');
const hasPassportStrategy = (strategy) =>
typeof passport._strategy === 'function' && passport._strategy(strategy) != null;
/**
* Custom Middleware to handle JWT authentication, with support for OpenID token reuse.
* Switches between JWT and OpenID authentication based on cookies and environment settings.
@ -13,17 +16,35 @@ const { isEnabled, tenantContextMiddleware } = require('@librechat/api');
const requireJwtAuth = (req, res, next) => {
const cookieHeader = req.headers.cookie;
const tokenProvider = cookieHeader ? cookies.parse(cookieHeader).token_provider : null;
const openidReuseEnabled = isEnabled(process.env.OPENID_REUSE_TOKENS);
const openidJwtAvailable = openidReuseEnabled && hasPassportStrategy('openidJwt');
const strategies =
tokenProvider === 'openid' && openidJwtAvailable
? ['openidJwt', 'jwt']
: ['jwt', ...(openidJwtAvailable ? ['openidJwt'] : [])];
const strategy =
tokenProvider === 'openid' && isEnabled(process.env.OPENID_REUSE_TOKENS) ? 'openidJwt' : 'jwt';
const authenticateWithStrategy = (index) => {
const strategy = strategies[index];
passport.authenticate(strategy, { session: false }, (err, user, info, status) => {
if (err) {
return next(err);
}
if (!user) {
if (index + 1 < strategies.length) {
return authenticateWithStrategy(index + 1);
}
return res.status(status || 401).json({
message: info?.message || 'Unauthorized',
});
}
req.user = user;
req.authStrategy = strategy;
// req.user is now populated by passport — set up tenant ALS context
tenantContextMiddleware(req, res, next);
})(req, res, next);
};
passport.authenticate(strategy, { session: false })(req, res, (err) => {
if (err) {
return next(err);
}
// req.user is now populated by passport — set up tenant ALS context
tenantContextMiddleware(req, res, next);
});
authenticateWithStrategy(0);
};
module.exports = requireJwtAuth;