passbolt/passbolt_api · error · ForbiddenException
The authentication token is expired.
Error message
The authentication token is expired.
What it means
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.
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
Defensive patterns
Strategy: try-catch
Validate before calling
const token = transfer.authenticationToken;
if (token && new Date(token.expired ?? token.created) < new Date()) {
await restartTransferSetup(); // pre-empt expiry
} Try / catch
try {
await api.updateTransfer(transferId, payload);
} catch (e) {
if (e.code === 403 && e.message.includes('token is expired')) {
await restartTransferSetup(); // new token, retry promptly
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The authentication token is missing.
- The authentication token is not active.
- The authentication token is not valid for this user.
- The authentication token type is invalid.
- This operation is not allowed for this user.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/5c73b30855632a70.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Mobile/src/Service/Transfers/TransfersUpdateService.php:176
private function assertOperationIsAllowed(Transfer $transfer, UserAccessControl $uac): void
{
if ($transfer->user_id !== $uac->getId()) {
throw new ForbiddenException(__('This operation is not allowed for this user.'));
}
if (!isset($transfer->authentication_token)) {
throw new ForbiddenException(__('The authentication token is missing.'));
}
if ($transfer->authentication_token->user_id !== $uac->getId()) {
throw new ForbiddenException(__('The authentication token is not valid for this user.'));
}
if ($transfer->authentication_token->type !== AuthenticationToken::TYPE_MOBILE_TRANSFER) {
throw new ForbiddenException(__('The authentication token type is invalid.'));
}
if ($transfer->authentication_token->active !== true) {
throw new ForbiddenException(__('The authentication token is not active.'));
}
if ($transfer->authentication_token->isExpired()) {
throw new ForbiddenException(__('The authentication token is expired.'));
}
}
/**
* Return an updated transfer entity.
*
* @param \Passbolt\Mobile\Model\Entity\Transfer $transfer entity
* @param array $data data
* @return \Passbolt\Mobile\Model\Entity\Transfer
*/
private function patchTransferEntity(Transfer $transfer, array $data): Transfer
{
$data['total_pages'] = $transfer->total_pages;
return $this->Transfers->patchEntity($transfer, $data, [
'accessibleFields' => [
'id' => true,
'user_id' => false,View on GitHub (pinned to 31c1bbc10f)