passbolt/passbolt_api · error · BadRequestException
The authentication token id is invalid.
Error message
The authentication token id is invalid.
What it means
BadRequestException thrown by AccountRecoveryContinueController::get() when the tokenId route parameter is missing or not a valid UUID. It follows the userId check and guards the authentication-token identifier format.
Solutions
- Regenerate the recovery link including the full authentication token UUID
- Validate the token id with Cake\Validation::uuid() client-side before navigating
- Confirm the email template renders the token id into the URL
- Check the route template accepts the token parameter and the client preserves it
Example fix
// before
$url = "/account-recovery/continue/{$userId}.json"; // token omitted
// after
$url = "/account-recovery/continue/{$userId}/{$accountRecoveryToken->id}.json"; Defensive patterns
Strategy: validation
Validate before calling
if (!isValidUuid(tokenId)) {
throw new Error('authentication token id must be a UUID');
} Type guard
function isValidUuid(value: unknown): value is string {
return typeof value === 'string'
&& /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
} Try / catch
try {
await accountRecoveryContinueService.get(userId, tokenId);
} catch (ApiError e) {
if (e.message.includes('token id is invalid')) {
showTokenLinkCorruptedScreen();
}
} Prevention
- Include the complete token UUID in recovery links generated by email templates
- Validate token ids client-side before calling the endpoint
- Never hardcode placeholder token ids in tests or docs
- Keep route templates and link builders in sync
When it happens
Trigger: GET request to the account recovery continue endpoint with a missing, empty, or non-UUID token id, e.g. /account-recovery/continue/<user-uuid>.json or with 'null'/'0' as token id.
Common situations: Recovery email link missing the token segment; client stripping the token when redirecting; expired/rotated token id replaced with a placeholder in tests.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The request data is invalid: id invalid.
- The user id is invalid.
- The user id is invalid.
- " " is not a valid search filter.
- " " is not a valid search filter. It is not a UTF8 string.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/221a72f385bd32b9.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/AccountRecovery/src/Controller/AccountRecoveryContinue/AccountRecoveryContinueController.php:66
/**
* Render a page to continue the account recovery process
*
* @param string|null $userId User ID
* @param string|null $tokenId Token ID
* @param \Passbolt\Ee\Service\AccountRecoveryContinue\AccountRecoveryContinueAggregatorService $accountRecoveryContinueService Service instance.
* @return void
* @throws \Cake\Http\Exception\BadRequestException if the data provided is not valid
*/
public function get(
?string $userId,
?string $tokenId,
AccountRecoveryContinueAggregatorService $accountRecoveryContinueService
): void {
if (!isset($userId) || !Validation::uuid($userId)) {
throw new BadRequestException(__('The user id is invalid.'));
}
if (!isset($tokenId) || !Validation::uuid($tokenId)) {
throw new BadRequestException(__('The authentication token id is invalid.'));
}
if ($this->getRequest()->is('json')) {
// Do not allow logged in user to recover
if ($this->User->role() !== Role::GUEST) {
throw new ForbiddenException(__('Only guests are allowed to proceed with account recovery.'));
}
(new AccountRecoveryRequestGetService())->getOrFail($userId, $tokenId);
$data = $accountRecoveryContinueService->get();
$this->success(__('The operation was successful.'), $data);
} else {
$this->renderHtml();
}
}
View on GitHub (pinned to 31c1bbc10f)