{"record":{"id":"a6638ca78348dc2d","repo":"passbolt/passbolt_api","slug":"the-resource-identifier-should-be-a-valid-uuid","errorCode":null,"errorMessage":"The resource identifier should be a valid UUID.","messagePattern":"The resource identifier should be a valid UUID\\.","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtTokenCreateService.php","lineNumber":47,"sourceCode":"{\n    public const JWT_SECRET_KEY_PATH = self::JWT_CONFIG_DIR . 'jwt.key';\n    public const JWT_ALG = 'RS256';\n    public const JWT_KEY_LENGTH = 4096;\n    public const JWT_EXPIRY_CONFIG_KEY = 'passbolt.auth.token.access_token.expiry';\n\n    protected string $keyPath = self::JWT_SECRET_KEY_PATH;\n\n    /**\n     * @param string $userId The id of the user successfully logging in.\n     * @param string|null $expiration The validity duration of the token in words (optional).\n     * @return string\n     * @throws \\InvalidArgumentException if the userId is not a valid Uuid\n     * @throws \\Passbolt\\JwtAuthentication\\Error\\Exception\\AccessToken\\InvalidJwtKeyPairException if the JWT secret key is not readable.\n     */\n    public function createToken(string $userId, ?string $expiration = null): string\n    {\n        if (!Validation::uuid($userId)) {\n            throw new InvalidArgumentException(__('The resource identifier should be a valid UUID.'));\n        }\n\n        $privateKey = $this->readKeyFileContent();\n        $payload = [\n            'iss' => Router::url('/', true),\n            'sub' => $userId,\n            'exp' => $this->createExpiryDate($expiration),\n        ];\n\n        return JWT::encode($payload, $privateKey, self::JWT_ALG);\n    }\n\n    /**\n     * Create a UNIX time from a time expressed in words.\n     * This should return an integer.\n     *\n     * @param string|null $expirationPeriod Expiration period in words.\n     * @return int Unix time","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Service/AccessToken/JwtTokenCreateService.php#L29-L65","documentation":"JwtTokenCreateService::createToken() validates that the $userId argument is a valid UUID with Validation::uuid() before signing a JWT. A non-UUID identifier throws this InvalidArgumentException, as documented in the method's @throws annotation.","triggerScenarios":"Calling createToken($userId, $expiration) with an empty string, an integer cast to string, an email address, or any string that is not a RFC 4122 UUID (e.g. '1', 'me', 'abc').","commonSituations":"Passing a user's username/email instead of id; using a null/empty value after a failed user lookup; calling createToken from custom code or tests with placeholder identifiers.","solutions":["Pass the user's id from the users table ( Cake\\Routing uses UuidFactory::uuid() format), e.g. $user->id from a UsersTable lookup","Validate the identifier before calling: \\Cake\\Validation\\Validation::uuid($userId)","If you only have a username/email, resolve it via UsersTable->find()->where(['username' => $email])->first() and use ->id","Fix test fixtures/callers that pass literal placeholder strings"],"exampleFix":"// before\n$jwt = $this->jwtService->createToken($user['username']);\n// after\nif (!\\Cake\\Validation\\Validation::uuid($user['id'])) {\n    throw new \\InvalidArgumentException('User id must be a UUID');\n}\n$jwt = $this->jwtService->createToken($user['id']);","handlingStrategy":"validation","validationCode":"use Cake\\Validation\\Validation;\nif (!Validation::uuid($userId)) { throw new \\InvalidArgumentException('$userId must be a UUID'); }","typeGuard":"function isUuid(mixed $id): bool {\n    return is_string($id) && \\Cake\\Validation\\Validation::uuid($id);\n}","tryCatchPattern":"try { $token = $service->createToken($userId); } catch (\\InvalidArgumentException $e) { // resolve the real user id from UsersTable before retrying }","preventionTips":["Always pass the users.id UUID, never username/email","Validate identifiers with Validation::uuid() at API boundaries","Fetch the user entity first and use ->id"],"tags":["jwt","uuid","validation","arguments"],"backgroundTag":"invalid-identifier-format","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"}