chore: clientId and clientSecret are not to be passed to the token endpoint
Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
@@ -548,8 +548,6 @@ describe('OidcRouter', () => {
|
||||
.send({
|
||||
grant_type: 'authorization_code',
|
||||
code: authorizationCode,
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret,
|
||||
redirect_uri: 'https://example.com/callback',
|
||||
})
|
||||
.expect(200);
|
||||
@@ -646,8 +644,6 @@ describe('OidcRouter', () => {
|
||||
.send({
|
||||
grant_type: 'authorization_code',
|
||||
code: authorizationCode,
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret,
|
||||
redirect_uri: 'https://example.com/callback',
|
||||
code_verifier: codeVerifier,
|
||||
})
|
||||
@@ -668,95 +664,8 @@ describe('OidcRouter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject token exchange with invalid client credentials', async () => {
|
||||
const {
|
||||
mocks: { auth, service, httpAuth },
|
||||
router,
|
||||
} = await createRouter(databaseId);
|
||||
|
||||
httpAuth.credentials.mockResolvedValueOnce({
|
||||
principal: {
|
||||
type: 'user',
|
||||
userEntityRef: 'user:default/test-user',
|
||||
},
|
||||
$$type: '@backstage/BackstageCredentials',
|
||||
});
|
||||
|
||||
auth.isPrincipal.mockReturnValueOnce(true);
|
||||
|
||||
const client = await service.registerClient({
|
||||
clientName: 'Test Client',
|
||||
redirectUris: ['https://example.com/callback'],
|
||||
responseTypes: ['code'],
|
||||
grantTypes: ['authorization_code'],
|
||||
scope: 'openid',
|
||||
});
|
||||
|
||||
const authSession = await service.createAuthorizationSession({
|
||||
clientId: client.clientId,
|
||||
redirectUri: 'https://example.com/callback',
|
||||
responseType: 'code',
|
||||
scope: 'openid',
|
||||
});
|
||||
|
||||
const { server } = await startTestBackend({
|
||||
features: [
|
||||
createBackendPlugin({
|
||||
pluginId: 'auth',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: { httpRouter: coreServices.httpRouter },
|
||||
async init({ httpRouter }) {
|
||||
httpRouter.use(router.getRouter());
|
||||
httpRouter.addAuthPolicy({
|
||||
path: '/',
|
||||
allow: 'unauthenticated',
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const approvalResponse = await request(server)
|
||||
.post(`/api/auth/v1/sessions/${authSession.id}/approve`)
|
||||
.set('Authorization', `Bearer ${MOCK_USER_TOKEN}`)
|
||||
.expect(200);
|
||||
|
||||
const redirectUrl = new URL(approvalResponse.body.redirectUrl);
|
||||
const authorizationCode = redirectUrl.searchParams.get('code');
|
||||
|
||||
const tokenResponse = await request(server)
|
||||
.post('/api/auth/v1/token')
|
||||
.send({
|
||||
grant_type: 'authorization_code',
|
||||
code: authorizationCode,
|
||||
client_id: client.clientId,
|
||||
client_secret: 'invalid-secret',
|
||||
redirect_uri: 'https://example.com/callback',
|
||||
})
|
||||
.expect(401);
|
||||
|
||||
expect(tokenResponse.body).toEqual({
|
||||
error: 'invalid_client',
|
||||
error_description: 'Invalid client credentials',
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject token exchange with invalid authorization code', async () => {
|
||||
const {
|
||||
mocks: { service },
|
||||
router,
|
||||
} = await createRouter(databaseId);
|
||||
|
||||
const client = await service.registerClient({
|
||||
clientName: 'Test Client',
|
||||
redirectUris: ['https://example.com/callback'],
|
||||
responseTypes: ['code'],
|
||||
grantTypes: ['authorization_code'],
|
||||
scope: 'openid',
|
||||
});
|
||||
const { router } = await createRouter(databaseId);
|
||||
|
||||
const { server } = await startTestBackend({
|
||||
features: [
|
||||
@@ -783,8 +692,6 @@ describe('OidcRouter', () => {
|
||||
.send({
|
||||
grant_type: 'authorization_code',
|
||||
code: 'invalid-code',
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret,
|
||||
redirect_uri: 'https://example.com/callback',
|
||||
})
|
||||
.expect(401);
|
||||
@@ -875,8 +782,6 @@ describe('OidcRouter', () => {
|
||||
.send({
|
||||
grant_type: 'authorization_code',
|
||||
code: authorizationCode,
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret,
|
||||
redirect_uri: 'https://example.com/callback',
|
||||
code_verifier: codeVerifier,
|
||||
})
|
||||
|
||||
@@ -276,13 +276,11 @@ export class OidcRouter {
|
||||
const {
|
||||
grant_type: grantType,
|
||||
code,
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
redirect_uri: redirectUri,
|
||||
code_verifier: codeVerifier,
|
||||
} = req.body;
|
||||
|
||||
if (!grantType || !code || !clientId || !clientSecret || !redirectUri) {
|
||||
if (!grantType || !code || !redirectUri) {
|
||||
this.logger.error(
|
||||
`Failed to exchange code for token: Missing required parameters`,
|
||||
);
|
||||
@@ -295,8 +293,6 @@ export class OidcRouter {
|
||||
try {
|
||||
const result = await this.oidc.exchangeCodeForToken({
|
||||
code,
|
||||
clientId,
|
||||
clientSecret,
|
||||
redirectUri,
|
||||
codeVerifier,
|
||||
grantType,
|
||||
|
||||
@@ -668,8 +668,6 @@ describe('OidcService', () => {
|
||||
|
||||
const tokenResult = await service.exchangeCodeForToken({
|
||||
code,
|
||||
clientId: client.clientId,
|
||||
clientSecret: client.clientSecret,
|
||||
redirectUri: 'https://example.com/callback',
|
||||
grantType: 'authorization_code',
|
||||
});
|
||||
@@ -689,47 +687,12 @@ describe('OidcService', () => {
|
||||
await expect(
|
||||
service.exchangeCodeForToken({
|
||||
code: 'test-code',
|
||||
clientId: 'test-client',
|
||||
clientSecret: 'test-secret',
|
||||
redirectUri: 'https://example.com/callback',
|
||||
grantType: 'client_credentials',
|
||||
}),
|
||||
).rejects.toThrow('Unsupported grant type');
|
||||
});
|
||||
|
||||
it('should throw error for invalid client', async () => {
|
||||
const { service } = await createOidcService(databaseId);
|
||||
|
||||
await expect(
|
||||
service.exchangeCodeForToken({
|
||||
code: 'test-code',
|
||||
clientId: 'invalid-client',
|
||||
clientSecret: 'test-secret',
|
||||
redirectUri: 'https://example.com/callback',
|
||||
grantType: 'authorization_code',
|
||||
}),
|
||||
).rejects.toThrow('Invalid client');
|
||||
});
|
||||
|
||||
it('should throw error for invalid client secret', async () => {
|
||||
const { service } = await createOidcService(databaseId);
|
||||
|
||||
const client = await service.registerClient({
|
||||
clientName: 'Test Client',
|
||||
redirectUris: ['https://example.com/callback'],
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.exchangeCodeForToken({
|
||||
code: 'test-code',
|
||||
clientId: client.clientId,
|
||||
clientSecret: 'invalid-secret',
|
||||
redirectUri: 'https://example.com/callback',
|
||||
grantType: 'authorization_code',
|
||||
}),
|
||||
).rejects.toThrow('Invalid client credentials');
|
||||
});
|
||||
|
||||
it('should handle PKCE verification', async () => {
|
||||
const { service, mocks } = await createOidcService(databaseId);
|
||||
const mockToken = 'mock-jwt-token';
|
||||
@@ -759,8 +722,6 @@ describe('OidcService', () => {
|
||||
|
||||
const tokenResult = await service.exchangeCodeForToken({
|
||||
code,
|
||||
clientId: client.clientId,
|
||||
clientSecret: client.clientSecret,
|
||||
redirectUri: 'https://example.com/callback',
|
||||
grantType: 'authorization_code',
|
||||
codeVerifier,
|
||||
@@ -792,8 +753,6 @@ describe('OidcService', () => {
|
||||
await expect(
|
||||
service.exchangeCodeForToken({
|
||||
code,
|
||||
clientId: client.clientId,
|
||||
clientSecret: client.clientSecret,
|
||||
redirectUri: 'https://example.com/callback',
|
||||
grantType: 'authorization_code',
|
||||
codeVerifier: 'invalid-verifier',
|
||||
|
||||
@@ -396,34 +396,16 @@ export class OidcService {
|
||||
|
||||
public async exchangeCodeForToken(params: {
|
||||
code: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
redirectUri: string;
|
||||
codeVerifier?: string;
|
||||
grantType: string;
|
||||
}) {
|
||||
const {
|
||||
code,
|
||||
clientId,
|
||||
clientSecret,
|
||||
redirectUri,
|
||||
codeVerifier,
|
||||
grantType,
|
||||
} = params;
|
||||
const { code, redirectUri, codeVerifier, grantType } = params;
|
||||
|
||||
if (grantType !== 'authorization_code') {
|
||||
throw new InputError('Unsupported grant type');
|
||||
}
|
||||
|
||||
const client = await this.oidc.getClient({ clientId });
|
||||
if (!client) {
|
||||
throw new AuthenticationError('Invalid client');
|
||||
}
|
||||
|
||||
if (client.clientSecret !== clientSecret) {
|
||||
throw new AuthenticationError('Invalid client credentials');
|
||||
}
|
||||
|
||||
const authCode = await this.oidc.getAuthorizationCode({ code });
|
||||
if (!authCode) {
|
||||
throw new AuthenticationError('Invalid authorization code');
|
||||
@@ -444,9 +426,6 @@ export class OidcService {
|
||||
if (!session) {
|
||||
throw new NotFoundError('Invalid authorization session');
|
||||
}
|
||||
if (session.clientId !== clientId) {
|
||||
throw new AuthenticationError('Client ID mismatch');
|
||||
}
|
||||
|
||||
if (session.redirectUri !== redirectUri) {
|
||||
throw new AuthenticationError('Redirect URI mismatch');
|
||||
|
||||
Reference in New Issue
Block a user