passbolt/passbolt_api · error · BadRequestException

The SSO authentication token is invalid. Token IP is…

Error message

The SSO authentication token is invalid. Token IP is missing.

What it means

A BadRequestException from assert() raised when the 'passbolt.security.userIp' check is enabled but the token's data payload lacks the IP property. getDataProperty(DATA_IP) throws AuthenticationTokenDataPropertyException, which is converted into this BadRequestException.

Solutions

  1. Restart the SSO flow so a fresh token is created with the IP data property under the current config
  2. Keep passbolt.security.userIp consistent between token creation and consumption (or restart flows after toggling it)
  3. Inspect the token's data JSON to confirm the ip property exists
  4. If the check is not required, explicitly set passbolt.security.userIp to false so the branch is skipped deterministically

Example fix

// before
// token created with userIp=false, consumed with userIp=true -> missing IP
// after
// create and consume under the same config, or generate a fresh token:
$token = $ssoTokenService->create($type, $userId, $ip, $userAgent, $settingsId);
Defensive patterns

Strategy: validation

Validate before calling

$ipEnabled = \Cake\Core\Configure::read('passbolt.security.userIp');
$hasIp = !$ipEnabled || $token->hasDataProperty(\Passbolt\Sso\Model\Entity\SsoAuthenticationToken::DATA_IP);

Try / catch

try {
    $service->assertAndConsume($token, $uac, $settingsId);
} catch (\Cake\Http\Exception\BadRequestException $e) {
    if (str_contains($e->getMessage(), 'Token IP is missing')) {
        // recreate the token under the current security config
    }
}

Prevention

When it happens

Trigger: assert()/assertAndConsume() runs with Configure 'passbolt.security.userIp' = true and the token data has no DATA_IP entry — tokens created with IP binding disabled (or before the feature) but asserted with it enabled, or corrupted/truncated token data.

Common situations: Config change between token creation and consumption (security.userIp turned on after tokens were minted without IP data); manually crafted tokens in tests; data JSON loss during a manual DB edit or 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/2740726c32d5b505. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Service/SsoAuthenticationTokens/SsoAuthenticationTokenGetService.php:191

        if ($token->isExpired()) {
            throw new BadRequestException($errorMsg . __('The authentication token is expired.'));
        }

        try {
            $sid = $token->getDataProperty(SsoAuthenticationToken::DATA_SSO_SETTING_ID);
        } catch (AuthenticationTokenDataPropertyException $exception) {
            throw new BadRequestException($errorMsg . __('Settings id is missing.'), 400, $exception);
        }

        if ($token->user_id !== $uac->getId() || !Validation::uuid($token->user_id)) {
            throw new BadRequestException($errorMsg . __('User id mismatch.'));
        }

        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.'));
            }
        }

View on GitHub (pinned to 31c1bbc10f)