passbolt/passbolt_api · error · OAuth2Exception

$data['error'] (dynamic provider error)

Error message

$data['error'] (dynamic provider error)

What it means

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.

Solutions

  1. Read the OAuth2Exception error/error_description to identify the provider's exact reason (e.g. invalid_grant, invalid_client).
  2. Restart the SSO login flow to obtain a fresh authorization code — codes expire within minutes and are single-use.
  3. Verify the client id, client secret, and redirect URI registered in the provider admin console match passbolt's SSO settings exactly.
  4. Check server clock synchronization (NTP) since expired codes/timestamps commonly cause invalid_grant.
Defensive patterns

Strategy: try-catch

Validate before calling

$body = json_decode((string)$response->getBody(), true);
if (isset($body['error'])) {
    // provider signalled failure; handle before constructing tokens
}

Type guard

function hasOAuthError(?array $data): bool {
    return !empty($data['error']);
}

Try / catch

try {
    $provider->checkResponse($response, $data);
} catch (OAuth2Exception $e) {
    // $e->getError() / description: e.g. invalid_grant -> restart login flow
}

Prevention

When it happens

Trigger: 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.

Common situations: 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`.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/7d4d1520508eb2b5. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Utility/OAuth2/Provider/OAuth2Provider.php:57

        parent::__construct($options, $collaborators);

        $this->grantFactory->setGrant('jwt_bearer', new JwtBearer());
    }

    /**
     * {@inheritDoc}
     *
     * @throws \Passbolt\Sso\Error\Exception\OAuth2Exception When error and error description is present
     * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException When unknown error faced
     */
    protected function checkResponse(ResponseInterface $response, $data): void
    {
        if (empty($data['error'])) {
            return;
        }

        if (is_string($data['error']) && isset($data['error_description']) && is_string($data['error_description'])) {
            throw new OAuth2Exception($data['error'], $data['error_description']);
        } else {
            throw new IdentityProviderException(
                $response->getReasonPhrase(),
                $response->getStatusCode(),
                (string)$response->getBody()
            );
        }
    }

    /**
     * @inheritDoc
     */
    protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface
    {
        return new OAuth2ResourceOwner($response);
    }
}

View on GitHub (pinned to 31c1bbc10f)