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

  1. Restart the SSO flow to create a fresh token that includes the user agent data
  2. Ensure the same passbolt.security.userAgent setting applies at creation and assertion time
  3. Verify the client sends a User-Agent header when initiating the flow (headless clients may omit it)
  4. 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

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.

Related errors


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)