passbolt/passbolt_api · error · ForbiddenException
The authentication token type is invalid.
Error message
The authentication token type is invalid.
What it means
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.
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
Example fix
// before $token = AuthenticationTokenFactory::make()->type(AuthenticationToken::TYPE_RECOVER)->...; // after $token = AuthenticationTokenFactory::make()->type(AuthenticationToken::TYPE_MOBILE_TRANSFER)->...;
Defensive patterns
Strategy: validation
Validate before calling
const token = transfer.authenticationToken;
if (token && token.type !== 'mobile-transfer') {
throw new Error('Wrong token type: must be mobile-transfer');
} Type guard
function isMobileTransferToken(t) {
return t?.authenticationToken?.type === 'mobile-transfer';
} Try / catch
try {
await api.updateTransfer(transferId, payload);
} catch (e) {
if (e.code === 403 && e.message.includes('token type is invalid')) {
// recreate the token with the mobile-transfer type via setup endpoint
}
} Prevention
- Create tokens only via the documented mobile transfer setup endpoint
- Verify token.type before starting page uploads
- Avoid hand-crafting authentication tokens in scripts
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The authentication token is expired.
- The authentication token is missing.
- The authentication token is not active.
- The authentication token is not valid for this user.
- This operation is not allowed for this user.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/f3d0c681f58f5fe8.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Mobile/src/Service/Transfers/TransfersUpdateService.php:170
* @param \App\Utility\UserAccessControl $uac user access control object
* @throws \Cake\Http\Exception\ForbiddenException if operation is not allowed for example:
* - Transfer or AuthToken is for another user
* - Authentication token is expired
* @return void
*/
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
{View on GitHub (pinned to 31c1bbc10f)