passbolt/passbolt_api · error · BadRequestException
The SSO authentication token is invalid. User agent is…
Error message
The SSO authentication token is invalid. User agent is missing.
What it means
A BadRequestException from assert() raised when the 'passbolt.security.userAgent' check is enabled but the token's data payload lacks the user agent property. getDataProperty(DATA_USER_AGENT) throws AuthenticationTokenDataPropertyException, converted into this BadRequestException.
Solutions
- Restart the SSO flow to create a fresh token that includes the user agent data
- Ensure the same passbolt.security.userAgent setting applies at creation and assertion time
- Verify the client sends a User-Agent header when initiating the flow (headless clients may omit it)
- Set passbolt.security.userAgent = false if UA pinning is not needed in your environment
Example fix
// before curl -X POST https://passbolt.example.com/sso/... # no User-Agent header -> token lacks UA data // after curl -A "my-client/1.0" -X POST https://passbolt.example.com/sso/...
Defensive patterns
Strategy: validation
Validate before calling
$uaEnabled = \Cake\Core\Configure::read('passbolt.security.userAgent');
$hasUa = !$uaEnabled || $token->hasDataProperty(\Passbolt\Sso\Model\Entity\SsoAuthenticationToken::DATA_USER_AGENT); Try / catch
try {
$service->assertAndConsume($token, $uac, $settingsId);
} catch (\Cake\Http\Exception\BadRequestException $e) {
if (str_contains($e->getMessage(), 'User agent is missing')) {
// ensure client sends User-Agent and recreate the token
}
} Prevention
- Ensure HTTP clients always send a User-Agent header
- Keep passbolt.security.userAgent consistent between token creation and assertion
- Create tokens through the SSO service so UA data is recorded
When it happens
Trigger: assert()/assertAndConsume() runs with Configure 'passbolt.security.userAgent' = true and the token data has no DATA_USER_AGENT entry — typically tokens created under different security config than the one used during assertion, or missing/corrupted token data.
Common situations: Config toggled between token creation and consumption; tokens seeded manually without user agent data; headless/API clients creating tokens without recording a user agent; data JSON lost on restore.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The SSO authentication token is invalid. Token IP is…
- SSO settings edit endpoints are disabled.
- The SSO authentication token is invalid. Settings id is…
- The SSO state is invalid. User agent mismatch.
- Access to this service requires an invitation. Please…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/7d9356ac56d04126.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Service/SsoAuthenticationTokens/SsoAuthenticationTokenGetService.php:203
}
if (Configure::read('passbolt.security.userIp')) {
try {
$ip = $token->getDataProperty(SsoAuthenticationToken::DATA_IP);
} catch (AuthenticationTokenDataPropertyException $exception) {
throw new BadRequestException($errorMsg . __('Token IP is missing.'), 400, $exception);
}
if ($ip !== $uac->getUserIp()) {
throw new BadRequestException($errorMsg . __('User IP mismatch.'));
}
}
if (Configure::read('passbolt.security.userAgent')) {
try {
$ua = $token->getDataProperty(SsoAuthenticationToken::DATA_USER_AGENT);
} catch (AuthenticationTokenDataPropertyException $exception) {
throw new BadRequestException($errorMsg . __('User agent is missing.'), 400, $exception);
}
if ($ua !== $uac->getUserAgent()) {
throw new BadRequestException($errorMsg . __('User agent mismatch.'));
}
}
if ($sid !== $settingsId || !Validation::uuid($sid)) {
throw new BadRequestException($errorMsg . __('Settings mismatch.'));
}
}
}
View on GitHub (pinned to 31c1bbc10f)