{"record":{"id":"f3d0c681f58f5fe8","repo":"passbolt/passbolt_api","slug":"the-authentication-token-type-is-invalid","errorCode":null,"errorMessage":"The authentication token type is invalid.","messagePattern":"The authentication token type is invalid\\.","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"plugins/PassboltCe/Mobile/src/Service/Transfers/TransfersUpdateService.php","lineNumber":170,"sourceCode":"     * @param \\App\\Utility\\UserAccessControl $uac user access control object\n     * @throws \\Cake\\Http\\Exception\\ForbiddenException if operation is not allowed for example:\n     * - Transfer or AuthToken is for another user\n     * - Authentication token is expired\n     * @return void\n     */\n    private function assertOperationIsAllowed(Transfer $transfer, UserAccessControl $uac): void\n    {\n        if ($transfer->user_id !== $uac->getId()) {\n            throw new ForbiddenException(__('This operation is not allowed for this user.'));\n        }\n        if (!isset($transfer->authentication_token)) {\n            throw new ForbiddenException(__('The authentication token is missing.'));\n        }\n        if ($transfer->authentication_token->user_id !== $uac->getId()) {\n            throw new ForbiddenException(__('The authentication token is not valid for this user.'));\n        }\n        if ($transfer->authentication_token->type !== AuthenticationToken::TYPE_MOBILE_TRANSFER) {\n            throw new ForbiddenException(__('The authentication token type is invalid.'));\n        }\n        if ($transfer->authentication_token->active !== true) {\n            throw new ForbiddenException(__('The authentication token is not active.'));\n        }\n        if ($transfer->authentication_token->isExpired()) {\n            throw new ForbiddenException(__('The authentication token is expired.'));\n        }\n    }\n\n    /**\n     * Return an updated transfer entity.\n     *\n     * @param \\Passbolt\\Mobile\\Model\\Entity\\Transfer $transfer entity\n     * @param array $data data\n     * @return \\Passbolt\\Mobile\\Model\\Entity\\Transfer\n     */\n    private function patchTransferEntity(Transfer $transfer, array $data): Transfer\n    {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Mobile/src/Service/Transfers/TransfersUpdateService.php#L152-L188","documentation":"Type guard for mobile transfers: the transfer's authentication token type does not match the expected mobile transfer type, meaning the token presented was minted for a different purpose, so the operation is denied with 403.","triggerScenarios":"Updating a transfer while the linked token is of another type (e.g. a recover or register token) — usually from a custom script creating the token with the wrong type constant, or fixture reuse across flows.","commonSituations":"Reusing an AuthenticationToken created for account recovery in the mobile transfer flow; API scripting mistakes passing a token from another feature; older tokens created before the mobile-transfer type existed.","solutions":["Create the token with AuthenticationToken::TYPE_MOBILE_TRANSFER via the mobile transfer setup endpoint","Verify the token's type column in authentication_tokens before use","Start the documented mobile transfer flow instead of hand-crafting tokens"],"exampleFix":"// before\n$token = AuthenticationTokenFactory::make()->type(AuthenticationToken::TYPE_RECOVER)->...;\n// after\n$token = AuthenticationTokenFactory::make()->type(AuthenticationToken::TYPE_MOBILE_TRANSFER)->...;","handlingStrategy":"validation","validationCode":"const token = transfer.authenticationToken;\nif (token && token.type !== 'mobile-transfer') {\n  throw new Error('Wrong token type: must be mobile-transfer');\n}","typeGuard":"function isMobileTransferToken(t) {\n  return t?.authenticationToken?.type === 'mobile-transfer';\n}","tryCatchPattern":"try {\n  await api.updateTransfer(transferId, payload);\n} catch (e) {\n  if (e.code === 403 && e.message.includes('token type is invalid')) {\n    // recreate the token with the mobile-transfer type via setup endpoint\n  }\n}","preventionTips":["Create tokens only via the documented mobile transfer setup endpoint","Verify token.type before starting page uploads","Avoid hand-crafting authentication tokens in scripts"],"tags":["mobile","transfer","authentication-token","token-type"],"backgroundTag":"invalid-enum-value","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"}