passbolt/passbolt_api · error · BadRequestException
The authentication token does not exist or has been deleted.
Error message
The authentication token does not exist or has been deleted.
What it means
Thrown when the SSO authentication token taken from the URL query cannot be found as an active, non-expired token of type SSO_RECOVER. The underlying SsoAuthenticationTokenGetService::getActiveNotExpiredOrFail raised a RecordNotFoundException (token absent or deleted) which the controller converts to this BadRequestException.
Solutions
- Restart the SSO recover flow from the beginning to obtain a fresh token, then use the new link only once.
- Verify the URL query token value is complete and unmodified (check for truncation by email clients or redirects).
- Check you are on the same passbolt instance/environment that issued the token.
- If tokens are being deleted prematurely, inspect cleanup/cron jobs and the sso_authentication_tokens table for the expected record.
Defensive patterns
Strategy: try-catch
Validate before calling
// Client-side: ensure the token query param is present and non-empty before navigating
const token = new URLSearchParams(window.location.search).get('token');
if (!token || token.length < 8) console.warn('Missing or truncated SSO recover token'); Type guard
function hasValidTokenShape(params) {
const t = params.get('token');
return typeof t === 'string' && /^[A-Za-z0-9_-]+$/.test(t) && t.length >= 16;
} Try / catch
try {
await completeSsoRecoverSuccess(token);
} catch (e) {
if (e.message.includes('does not exist or has been deleted')) {
restartSsoRecoverFlow(); // token consumed/missing: get a fresh one
}
} Prevention
- Treat SSO recover tokens as strictly single-use; never reuse the success URL.
- Copy recovery links without truncation (email clients often wrap URLs).
- Keep the recovery flow within one environment/instance.
- Avoid refreshing the success page; restart the flow if it fails.
When it happens
Trigger: GET /sso/recover/success/azure?token=... where the token value does not match any sso_authentication_tokens row: token already consumed by a previous success call, manually deleted, mistyped, or from a different environment/database.
Common situations: User refreshes the success page after the token was already used (single-use token consumed), replaying an old recovery link, or pointing a staging URL at a database where the token was never created.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The authentication token does not exist or has been deleted.
- The authentication token does not exist or has been deleted.
- The authentication token has been expired.
- Ajax/Json request not supported.
- It is not possible to create an authentication token for…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/75783a5d21e951e4.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/SsoRecover/src/Controller/Azure/AzureRecoverSuccessController.php:56
}
/**
* @return void
* @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
*/
public function ssoRecoverSuccess(): void
{
if ($this->request->is('json')) {
throw new BadRequestException(__('Ajax/Json request not supported.'));
}
$this->User->assertNotLoggedIn();
$token = $this->getTokenFromUrlQuery();
try {
(new SsoAuthenticationTokenGetService())->getActiveNotExpiredOrFail($token, SsoState::TYPE_SSO_RECOVER);
} catch (RecordNotFoundException $e) {
throw new BadRequestException(
__('The authentication token does not exist or has been deleted.'),
null,
$e
);
} catch (CustomValidationException $e) {
throw new BadRequestException(
__('The authentication token has been expired.'),
null,
$e
);
}
$this->viewBuilder()
->setTheme('Passbolt/Sso')
->setLayout('default')
->setTemplatePath('success')
->setTemplate('stage3');
}View on GitHub (pinned to 31c1bbc10f)