{"record":{"id":"7d4d1520508eb2b5","repo":"passbolt/passbolt_api","slug":"data-error-dynamic-provider-error-oauth2provider","errorCode":null,"errorMessage":"$data['error'] (dynamic provider error)","messagePattern":"\\$data\\['error'\\] \\(dynamic provider error\\)","errorType":"exception","errorClass":"OAuth2Exception","httpStatus":null,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Utility/OAuth2/Provider/OAuth2Provider.php","lineNumber":57,"sourceCode":"        parent::__construct($options, $collaborators);\n\n        $this->grantFactory->setGrant('jwt_bearer', new JwtBearer());\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @throws \\Passbolt\\Sso\\Error\\Exception\\OAuth2Exception When error and error description is present\n     * @throws \\League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException When unknown error faced\n     */\n    protected function checkResponse(ResponseInterface $response, $data): void\n    {\n        if (empty($data['error'])) {\n            return;\n        }\n\n        if (is_string($data['error']) && isset($data['error_description']) && is_string($data['error_description'])) {\n            throw new OAuth2Exception($data['error'], $data['error_description']);\n        } else {\n            throw new IdentityProviderException(\n                $response->getReasonPhrase(),\n                $response->getStatusCode(),\n                (string)$response->getBody()\n            );\n        }\n    }\n\n    /**\n     * @inheritDoc\n     */\n    protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface\n    {\n        return new OAuth2ResourceOwner($response);\n    }\n}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Utility/OAuth2/Provider/OAuth2Provider.php#L39-L75","documentation":"OAuth2Provider::checkResponse inspects the token endpoint's decoded JSON body; when it contains an `error` field the OAuth2 spec says the request failed. If both `error` and `error_description` are strings, the library throws OAuth2Exception carrying those dynamic provider-supplied values; otherwise it falls back to IdentityProviderException. The message text is thus dictated by the identity provider, not passbolt.","triggerScenarios":"Any OAuth2 token/authorization request whose HTTP response body parses to JSON containing a non-empty `error` key — e.g. code exchange with an expired/already-used authorization code, bad client_id/client_secret, or redirect_uri mismatch.","commonSituations":"Replaying an authorization code (they are single-use); clock skew invalidating codes; misconfigured client secret after rotating credentials in Azure/Google admin consoles; provider returning structured errors like `invalid_grant`.","solutions":["Read the OAuth2Exception error/error_description to identify the provider's exact reason (e.g. invalid_grant, invalid_client).","Restart the SSO login flow to obtain a fresh authorization code — codes expire within minutes and are single-use.","Verify the client id, client secret, and redirect URI registered in the provider admin console match passbolt's SSO settings exactly.","Check server clock synchronization (NTP) since expired codes/timestamps commonly cause invalid_grant."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"$body = json_decode((string)$response->getBody(), true);\nif (isset($body['error'])) {\n    // provider signalled failure; handle before constructing tokens\n}","typeGuard":"function hasOAuthError(?array $data): bool {\n    return !empty($data['error']);\n}","tryCatchPattern":"try {\n    $provider->checkResponse($response, $data);\n} catch (OAuth2Exception $e) {\n    // $e->getError() / description: e.g. invalid_grant -> restart login flow\n}","preventionTips":["Never reuse authorization codes; always start a fresh OAuth flow on failure","Keep client id/secret/redirect URI in sync with the provider console","Run NTP on servers to avoid invalid_grant from clock skew"],"tags":["oauth2","sso","identity-provider","http-response"],"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"}