{"record":{"id":"509333d275515850","repo":"passbolt/passbolt_api","slug":"e-getmessage-from-oauth2exception-during-admin-sso-setup","errorCode":null,"errorMessage":"$e->getMessage() from OAuth2Exception during admin SSO setup (dynamic), remapped to 400","messagePattern":"\\$e->getMessage\\(\\) from OAuth2Exception during admin SSO setup \\(dynamic\\), remapped to 400","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Controller/AbstractSso2Stage2Controller.php","lineNumber":225,"sourceCode":"     * @param \\App\\Service\\Cookie\\AbstractSecureCookieService $cookieService Cookie service\n     * @param \\Passbolt\\Sso\\Model\\Entity\\SsoState $ssoState SSO state.\n     * @param string $code jwt\n     * @return void\n     */\n    protected function stage2AsAdmin(AbstractSecureCookieService $cookieService, SsoState $ssoState, string $code): void\n    {\n        try {\n            // Get the draft settings\n            $settingsDto = (new SsoSettingsGetService())->getDraftByIdOrFail($ssoState->sso_settings_id, true);\n        } catch (Exception $exception) {\n            throw new BadRequestException($exception->getMessage(), 400, $exception);\n        }\n\n        try {\n            $service = $this->ssoServiceFactory($cookieService, $settingsDto);\n            $uac = $service->assertStateCodeAndGetUac($ssoState, $code, $this->User->ip(), $this->User->userAgent());\n        } catch (OAuth2Exception $e) { // Remap 500 error with 400 when admin is setting up SSO\n            throw new BadRequestException($e->getMessage(), 400, $e);\n        }\n\n        // Create authentication token for next step, e.g. activate settings\n        $ssoAuthToken = $service->createAuthTokenToActiveSettings($uac, $service->getSettings()->id);\n\n        $this->response = $this->getResponse()->withCookie($service->clearStateCookie());\n        $this->redirect(Router::url(\"/sso/login/dry-run/success?token={$ssoAuthToken->token}\", true));\n    }\n}\n","sourceCodeStart":207,"sourceCodeEnd":235,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Controller/AbstractSso2Stage2Controller.php#L207-L235","documentation":"During admin SSO setup stage2, assertStateCodeAndGetUac() exchanges the OAuth2 code with the provider and validates the state code. Any OAuth2Exception (token exchange failure, invalid code, wrong redirect_uri, provider error response) is remapped from a 500-level OAuth2Exception to a 400 BadRequestException carrying its dynamic message, with the original chained.","triggerScenarios":"Admin finishes the OAuth2 redirect and the controller calls assertStateCodeAndGetUac(); the provider rejects the code — expired/already-used authorization code, mismatched client_secret, wrong redirect URI, or misconfigured provider endpoints.","commonSituations":"Wrong client secret or redirect URI in the SSO draft settings; provider (Azure AD, Google, etc.) clock skew invalidating codes; user replaying the callback URL (code is single-use); network/DNS issues reaching the provider's token endpoint during setup.","solutions":["Re-read the message in the 400 response — it names the provider-side cause (e.g. invalid_grant, redirect_uri_mismatch) and fix the corresponding SSO draft setting.","Restart the SSO setup from the admin settings screen to get a fresh authorization code; codes are single-use and expire in minutes.","Verify client id, client secret, and redirect URI in the draft exactly match the provider's app registration.","Check server outbound connectivity to the provider's token endpoint (firewall/proxy)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!clientId || !clientSecret || !redirectUri) { throw new Error('SSO provider config incomplete before starting OAuth flow'); }","typeGuard":"function isOAuth2Exception(e) { return e && (e.name === 'OAuth2Exception' || /^OAuth2/.test(String(e.class))); }","tryCatchPattern":"try { await stage2AsAdmin(state, code); } catch (e) { if (e.status === 400 && /invalid_grant|redirect_uri_mismatch|invalid_client/.test(e.message)) { fixProviderSettings(e.message); restartSetup(); } else { throw e; } }","preventionTips":["Verify client id/secret/redirect URI against the provider app registration before setup","Use each authorization code exactly once and within minutes of issuance","Check outbound network access to the provider token endpoint","Read the chained provider message to pinpoint the misconfiguration"],"tags":["sso","oauth2","token-exchange","admin-setup","bad-request"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}