passbolt/passbolt_api · error · BadRequestException
The code is required in request data.
Error message
The code is required in request data.
What it means
The POST-based SSO verification endpoints require a 'code' field in the request data (the authorization code or verify code). If it is unset or not a string, the controller throws this 400 because the subsequent state/token exchange cannot proceed.
Solutions
- Include the 'code' string field in the request body exactly as issued in the earlier step.
- Send the request with the correct Content-Type (application/json) so CakePHP parses the body into request data.
- Restart the SSO flow if the code was already consumed — get a fresh one from stage1.
- Upgrade/fix the client integration to the current SSO v2 payload schema.
Example fix
// before
fetch('/sso/verify', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({state})});
// after
fetch('/sso/verify', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({state, code: authCode})}); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof code !== 'string' || code.length === 0) { throw new Error('code must be a non-empty string before POSTing'); }
await fetch(url, {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({state, code})}); Type guard
function isNonEmptyString(v) { return typeof v === 'string' && v.length > 0; } Try / catch
try { await api.post('/sso/verify', {state, code}); } catch (e) { if (e.status === 400 && /code is required in request data/.test(e.message)) { checkPayloadAndContentType(); } else { throw e; } } Prevention
- Always include the code field as a string in the POST body
- Set Content-Type: application/json so the body parses
- Keep client payload schema in sync with SSO v2 API
- Fetch a fresh code if the previous one was consumed
When it happens
Trigger: POST to an SSO endpoint that calls getCodeFromRequestData() with a body missing 'code', or where 'code' is not a string (null, object, number) — including bodies sent with the wrong Content-Type so the data does not parse.
Common situations: Client bug omitting the code field in the stage2 payload; JSON sent without Content-Type: application/json so getData() sees an empty array; legacy client versions using a different payload schema; proxy/gateway stripping the body.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Could not save the SSO state, invalid nonce.
- Could not validate the SSO recover request.
- Invalid status.
- It is not possible to create an authentication token for…
- It is not possible to save the SSO settings.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/ff39fc5f09132367.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Controller/AbstractSsoController.php:164
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;
}
/**
* @throws \Cake\Http\Exception\BadRequestException if the user_id is not provided in URL query
* @return \App\Utility\ExtendedUserAccessControl
*/
public function getUacFromData(): ExtendedUserAccessControl
{
$userId = $this->request->getData('user_id');
if (!isset($userId) || !is_string($userId)) {
throw new BadRequestException(__('The user id is required in URL parameters.'));
}
return $this->getUacFromUserIdAndRequest($userId);
}View on GitHub (pinned to 31c1bbc10f)