passbolt/passbolt_api · error · BadRequestException
The code is required in URL parameters.
Error message
The code is required in URL parameters.
What it means
The OAuth2 callback must carry the authorization 'code' query parameter issued by the identity provider. If it is unset or not a string, the controller cannot perform the token exchange and throws this 400.
Solutions
- Inspect the callback URL for an 'error' query parameter — the provider refused the request (e.g. consent denied); have the user retry and approve.
- Verify the redirect URI registered with the provider exactly matches the passbolt SSO settings.
- Restart the SSO flow; authorization codes are single-use and short-lived.
- Check provider status/endpoint configuration if error redirects occur for all users.
Defensive patterns
Strategy: validation
Validate before calling
const params = new URL(callbackUrl).searchParams;
if (!params.get('error') && typeof params.get('code') !== 'string') { throw new Error('No authorization code and no error param — check provider redirect config'); } Type guard
function hasCodeParam(url) { return typeof new URL(url).searchParams.get('code') === 'string'; } Try / catch
try { await ssoStage2(url); } catch (e) { if (e.status === 400 && /code is required/.test(e.message)) { const err = new URL(url).searchParams.get('error'); handleProviderError(err || 'missing code'); restartFlow(); } else { throw e; } } Prevention
- Match the provider-registered redirect URI exactly
- Handle provider error redirects (error=access_denied) explicitly
- Use codes once, promptly — never replay callback URLs
- Monitor provider status for outage-driven error redirects
When it happens
Trigger: GET to the SSO stage2 callback without ?code=..., or with a non-string value — often because the provider redirected with an error parameter (error/error_description) instead of a code.
Common situations: User denied consent at the provider (redirect contains error=access_denied, no code); wrong callback URL configured at the provider; provider outage returning an error redirect; user bookmarking/replaying a URL after the code was consumed.
Related errors
- AccessToken should be an instance of BaseIdToken class.
- Cannot parse JWKS endpoint response.
- $data['error'] (dynamic provider error)
- $data['error'] (dynamic provider error)
- $data['error'] (dynamic provider error)
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/c8838e3289d7d347.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php:150
public function getStateFromUrlQuery(): string
{
$state = $this->request->getQuery('state');
if (!is_string($state) || !SsoState::isValidState($state)) {
throw new BadRequestException(__('The state is required in URL parameters.'));
}
return $state;
}
/**
* @throws \Cake\Http\Exception\BadRequestException if the code (access token) is not provided in URL query
* @return string code
*/
public function getCodeFromUrlQuery(): string
{
$code = $this->request->getQuery('code');
if (!isset($code) || !is_string($code)) {
throw new BadRequestException(__('The code is required in URL parameters.'));
}
return $code;
}
/**
* @throws \Cake\Http\Exception\BadRequestException if the code (access token) is not provided in request data
* @return string code
*/
public function getCodeFromRequestData(): string
{
$code = $this->getRequest()->getData('code');
if (!isset($code) || !is_string($code)) {
throw new BadRequestException(__('The code is required in request data.'));
}
return $code;
}View on GitHub (pinned to 31c1bbc10f)