{"record":{"id":"5c73b30855632a70","repo":"passbolt/passbolt_api","slug":"the-authentication-token-is-expired","errorCode":null,"errorMessage":"The authentication token is expired.","messagePattern":"The authentication token is expired\\.","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"plugins/PassboltCe/Mobile/src/Service/Transfers/TransfersUpdateService.php","lineNumber":176,"sourceCode":"    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    {\n        $data['total_pages'] = $transfer->total_pages;\n\n        return $this->Transfers->patchEntity($transfer, $data, [\n            'accessibleFields' => [\n                'id' => true,\n                'user_id' => false,","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Mobile/src/Service/Transfers/TransfersUpdateService.php#L158-L194","documentation":"Expiry guard for mobile transfers: the transfer's authentication token creation time is past its validity window, so the token is expired and the transfer operation is denied with 403; a fresh transfer must be started.","triggerScenarios":"Resuming or completing a mobile transfer long after the token was issued — e.g. app suspended for days, network interruption causing a late retry, or slow manual page-by-page uploads past the token TTL.","commonSituations":"Mobile app left idle during transfer setup; user abandoning setup and resuming later; clock/timezone issues making tokens appear expired; token TTL changed in config between creation and use.","solutions":["Restart the mobile transfer flow to obtain a new token and complete it promptly","Complete the transfer within the token validity window","Verify server/client clocks are synchronized (NTP) to avoid false expiry"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const token = transfer.authenticationToken;\nif (token && new Date(token.expired ?? token.created) < new Date()) {\n  await restartTransferSetup(); // pre-empt expiry\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.updateTransfer(transferId, payload);\n} catch (e) {\n  if (e.code === 403 && e.message.includes('token is expired')) {\n    await restartTransferSetup(); // new token, retry promptly\n  }\n}","preventionTips":["Complete the transfer promptly after setup; don't leave it idle for days","Keep device and server clocks NTP-synchronized","Design the client to auto-restart the flow on expiry instead of retrying with the dead token"],"tags":["mobile","transfer","authentication-token","expired"],"backgroundTag":"jwt-token-expired","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"}