Add OIDC ID token support (#680)

This commit is contained in:
Daniel Kelleher 2025-07-14 14:22:04 +02:00 • committed by GitHub
commit 5b99c24bda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 18 deletions

View file

@ -16,6 +16,18 @@ jest.mock('pkce-challenge', () => ({
})
}));
const mockTokens = {
access_token: 'mock_access_token',
token_type: 'bearer',
expires_in: 3600,
refresh_token: 'mock_refresh_token'
};
const mockTokensWithIdToken = {
...mockTokens,
id_token: 'mock_id_token'
}
describe('Token Handler', () => {
// Mock client data
const validClient: OAuthClientInformationFull = {
@ -58,12 +70,7 @@ describe('Token Handler', () => {
async exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string): Promise<OAuthTokens> {
if (authorizationCode === 'valid_code') {
return {
access_token: 'mock_access_token',
token_type: 'bearer',
expires_in: 3600,
refresh_token: 'mock_refresh_token'
};
return mockTokens;
}
throw new InvalidGrantError('The authorization code is invalid or has expired');
},
@ -291,18 +298,36 @@ describe('Token Handler', () => {
);
});
it('returns id token in code exchange if provided', async () => {
mockProvider.exchangeAuthorizationCode = async (client: OAuthClientInformationFull, authorizationCode: string): Promise<OAuthTokens> => {
if (authorizationCode === 'valid_code') {
return mockTokensWithIdToken;
}
throw new InvalidGrantError('The authorization code is invalid or has expired');
};
const response = await supertest(app)
.post('/token')
.type('form')
.send({
client_id: 'valid-client',
client_secret: 'valid-secret',
grant_type: 'authorization_code',
code: 'valid_code',
code_verifier: 'valid_verifier'
});
expect(response.status).toBe(200);
expect(response.body.id_token).toBe('mock_id_token');
});
it('passes through code verifier when using proxy provider', async () => {
const originalFetch = global.fetch;
try {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({
access_token: 'mock_access_token',
token_type: 'bearer',
expires_in: 3600,
refresh_token: 'mock_refresh_token'
})
json: () => Promise.resolve(mockTokens)
});
const proxyProvider = new ProxyOAuthServerProvider({
@ -359,12 +384,7 @@ describe('Token Handler', () => {
try {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({
access_token: 'mock_access_token',
token_type: 'bearer',
expires_in: 3600,
refresh_token: 'mock_refresh_token'
})
json: () => Promise.resolve(mockTokens)
});
const proxyProvider = new ProxyOAuthServerProvider({

View file

@ -62,6 +62,7 @@ export const OAuthMetadataSchema = z
export const OAuthTokensSchema = z
.object({
access_token: z.string(),
id_token: z.string().optional(), // Optional for OAuth 2.1, but necessary in OpenID Connect
token_type: z.string(),
expires_in: z.number().optional(),
scope: z.string().optional(),