passbolt/passbolt_api · error · BadRequestException
Single sign-on failed. Provider error
Error message
Single sign-on failed. Provider error: "{0}" What it means
getResourceOwner() exchanges the OAuth code with the identity provider; when the League OAuth2 provider throws IdentityProviderException, the message is logged and re-thrown as BadRequestException 'Single sign-on failed. Provider error: "{0}"' embedding the provider's error message. It surfaces upstream IdP failures to the passbolt client.
Solutions
- Read the embedded provider error in the message and check the passbolt error logs (Log::error includes response body) for details
- Verify SSO settings: client id, client secret, redirect URI, token endpoint match the IdP app configuration
- Regenerate the client secret if rotated on the provider, then update passbolt SSO settings
- Restart the SSO flow with a fresh authorization code (codes are single-use and short-lived)
- Check network egress from the passbolt server to the IdP token endpoint
Example fix
// before 'client_secret' => 'old-revoked-secret' // after 'client_secret' => '<new-secret-from-provider>' // then re-run `passbolt sso_settings set`
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: verify settings and fresh code
if (!Validation::uuid($settingsId) || empty($code)) {
throw new \InvalidArgumentException('SSO settings id and fresh auth code required');
} Try / catch
try {
$owner = $service->getResourceOwnerAndAssertAgainstUser($provider, $code, $ip, $ua);
} catch (BadRequestException $e) {
Log::error('SSO provider error: ' . $e->getMessage());
// retry with a fresh authorization code or fix provider settings
} Prevention
- Never reuse authorization codes; always restart the OAuth flow
- Keep provider client id/secret/redirect URI in sync with the IdP app
- Monitor server logs for the full provider response body
- Watch for provider-side secret rotation and config changes
When it happens
Trigger: Authorization code is invalid, expired, or already used; client_id/client_secret mismatch with the IdP; token endpoint URL wrong or unreachable; IdP rejects redirect_uri; account/tenant disabled on the provider side.
Common situations: Clock skew invalidating tokens; Azure AD tenant/app config changed; wrong environment credentials (staging secret on production); replayed callback (code single-use); provider outage.
Related errors
- $data['error'] (dynamic provider error)
- $data['error'] (dynamic provider error)
- $e->getMessage() from OAuth2Exception during admin SSO…
- error
- error
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/6ff393ba0b4ab00c.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Service/Sso/AbstractSsoService.php:261
try {
// Try to get an access token using the authorization code grant.
/** @var \League\OAuth2\Client\Token\AccessToken $accessToken */
$accessToken = $this->provider->getAccessToken('authorization_code', ['code' => $code]);
// Using the access token id_token, we may look up details about the resource owner.
$resourceOwner = $this->provider->getResourceOwner($accessToken);
} catch (IdentityProviderException $exception) {
$msg = "Error while getting access token. Message: {$exception->getMessage()}, ";
if (!is_string($exception->getResponseBody())) {
$msg .= 'Response: ' . json_encode($exception->getResponseBody());
} else {
$msg .= "Response: {$exception->getResponseBody()}";
}
Log::error($msg);
$msg = __('Single sign-on failed.') . ' ' . __('Provider error: "{0}"', $exception->getMessage());
throw new BadRequestException($msg, 400, $exception);
}
// Helper for developers working on new providers
if (!($resourceOwner instanceof SsoResourceOwnerInterface)) {
$msg = 'Provider must return a ResourceOwner that implements ResourceOwnerWithEmailInterface.';
throw new InternalErrorException($msg);
}
$email = $resourceOwner->getEmail();
if (!isset($email) || !is_string($email) || !EmailValidationRule::check($email)) {
$msg = __('Single sign-on failed.') . ' ' . __('Email not provided by provider.');
throw new BadRequestException($msg);
}
return $resourceOwner;
}
/**View on GitHub (pinned to 31c1bbc10f)