{"record":{"id":"2740726c32d5b505","repo":"passbolt/passbolt_api","slug":"the-sso-authentication-token-is-invalid-token-ip-is-missing","errorCode":null,"errorMessage":"The SSO authentication token is invalid. Token IP is missing.","messagePattern":"The SSO authentication token is invalid\\. Token IP is missing\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Service/SsoAuthenticationTokens/SsoAuthenticationTokenGetService.php","lineNumber":191,"sourceCode":"        if ($token->isExpired()) {\n            throw new BadRequestException($errorMsg . __('The authentication token is expired.'));\n        }\n\n        try {\n            $sid = $token->getDataProperty(SsoAuthenticationToken::DATA_SSO_SETTING_ID);\n        } catch (AuthenticationTokenDataPropertyException $exception) {\n            throw new BadRequestException($errorMsg . __('Settings id is missing.'), 400, $exception);\n        }\n\n        if ($token->user_id !== $uac->getId() || !Validation::uuid($token->user_id)) {\n            throw new BadRequestException($errorMsg . __('User id mismatch.'));\n        }\n\n        if (Configure::read('passbolt.security.userIp')) {\n            try {\n                $ip = $token->getDataProperty(SsoAuthenticationToken::DATA_IP);\n            } catch (AuthenticationTokenDataPropertyException $exception) {\n                throw new BadRequestException($errorMsg . __('Token IP is missing.'), 400, $exception);\n            }\n\n            if ($ip !== $uac->getUserIp()) {\n                throw new BadRequestException($errorMsg . __('User IP mismatch.'));\n            }\n        }\n\n        if (Configure::read('passbolt.security.userAgent')) {\n            try {\n                $ua = $token->getDataProperty(SsoAuthenticationToken::DATA_USER_AGENT);\n            } catch (AuthenticationTokenDataPropertyException $exception) {\n                throw new BadRequestException($errorMsg . __('User agent is missing.'), 400, $exception);\n            }\n            if ($ua !== $uac->getUserAgent()) {\n                throw new BadRequestException($errorMsg . __('User agent mismatch.'));\n            }\n        }\n","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Service/SsoAuthenticationTokens/SsoAuthenticationTokenGetService.php#L173-L209","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Restart the SSO flow so a fresh token is created with the IP data property under the current config","Keep passbolt.security.userIp consistent between token creation and consumption (or restart flows after toggling it)","Inspect the token's data JSON to confirm the ip property exists","If the check is not required, explicitly set passbolt.security.userIp to false so the branch is skipped deterministically"],"exampleFix":"// before\n// token created with userIp=false, consumed with userIp=true -> missing IP\n// after\n// create and consume under the same config, or generate a fresh token:\n$token = $ssoTokenService->create($type, $userId, $ip, $userAgent, $settingsId);","handlingStrategy":"validation","validationCode":"$ipEnabled = \\Cake\\Core\\Configure::read('passbolt.security.userIp');\n$hasIp = !$ipEnabled || $token->hasDataProperty(\\Passbolt\\Sso\\Model\\Entity\\SsoAuthenticationToken::DATA_IP);","typeGuard":null,"tryCatchPattern":"try {\n    $service->assertAndConsume($token, $uac, $settingsId);\n} catch (\\Cake\\Http\\Exception\\BadRequestException $e) {\n    if (str_contains($e->getMessage(), 'Token IP is missing')) {\n        // recreate the token under the current security config\n    }\n}","preventionTips":["Keep passbolt.security.userIp consistent across token lifecycle","Create tokens with IP data when the check is enabled","Restart SSO flows after changing security configuration"],"tags":["sso","missing-data","security-config","ip-binding"],"backgroundTag":"missing-required-config-field","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}