Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 7d8649278d fix(auth): handle missing state param in OIDC callback gracefully
https://sonarly.com/issue/35716?type=bug

The OIDC SSO authentication callback endpoint throws an unhandled error when the `state` query parameter is missing or not in the expected JSON format, causing SSO login failures.

Fix: Changed `throw new Error('Invalid OIDC identity provider params')` to `throw new AuthException('Invalid OIDC identity provider params', AuthExceptionCode.INVALID_DATA)` in the `getStateByRequest()` method.

This fix:
1. Uses the proper exception type (`AuthException`) that is already used for all other validation errors in the same file and in the sibling `SAMLAuthGuard`
2. The `GuardRedirectService.captureException()` method filters out `AuthException` with non-INTERNAL_SERVER_ERROR codes (lines 70-75), so this error will no longer be sent to Sentry
3. The error is still properly handled - user gets redirected with an appropriate error message
4. Added two test cases to verify the behavior when state param is missing or malformed
2026-05-07 17:54:14 +00:00
2 changed files with 24 additions and 1 deletions
@@ -49,7 +49,10 @@ export class OIDCAuthGuard extends AuthGuard('openidconnect') {
};
}
throw new Error('Invalid OIDC identity provider params');
throw new AuthException(
'Invalid OIDC identity provider params',
AuthExceptionCode.INVALID_DATA,
);
}
async canActivate(context: ExecutionContext): Promise<boolean> {
@@ -135,4 +135,24 @@ describe('OIDCAuthGuard', () => {
await expect(guard.canActivate(mockExecutionContext)).resolves.toBe(false);
expect(guardRedirectService.dispatchErrorFromGuard).toHaveBeenCalled();
});
it('should handle missing state param and identityProviderId with AuthException', async () => {
const mockedRequest = createMockedRequest({}, {});
mockExecutionContext = createMockExecutionContext(mockedRequest);
await expect(guard.canActivate(mockExecutionContext)).resolves.toBe(false);
expect(guardRedirectService.dispatchErrorFromGuard).toHaveBeenCalled();
expect(ssoService.findSSOIdentityProviderById).not.toHaveBeenCalled();
});
it('should handle malformed state param with AuthException', async () => {
const mockedRequest = createMockedRequest({}, { state: 'not-json' });
mockExecutionContext = createMockExecutionContext(mockedRequest);
await expect(guard.canActivate(mockExecutionContext)).resolves.toBe(false);
expect(guardRedirectService.dispatchErrorFromGuard).toHaveBeenCalled();
expect(ssoService.findSSOIdentityProviderById).not.toHaveBeenCalled();
});
});