From 7d8649278d3d970476ba830e20b9dee2e35c38f6 Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Thu, 7 May 2026 17:54:14 +0000 Subject: [PATCH] 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 --- .../auth/guards/oidc-auth.guard.ts | 5 ++++- .../auth/guards/oidc-auth.spec.ts | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.guard.ts index a8ae21133e1..1048b02b3b2 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.guard.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.guard.ts @@ -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 { diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.spec.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.spec.ts index 7cef1ef262d..46a16631a97 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/oidc-auth.spec.ts @@ -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(); + }); });