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_RECOVER authentication token from the URL query is not found as an active token; getActiveNotExpiredOrFail raised RecordNotFoundException and the controller wraps it in this BadRequestException. Tokens are single-use, so a missing token usually means it was already consumed or never existed.
Solutions
- Restart the SSO recovery flow to receive a fresh token and use the new link exactly once.
- Verify the token parameter is complete and unaltered (URL-encoding, email client truncation).
- Confirm the request targets the same passbolt instance that issued the token.
- Avoid refreshing/re-submitting the success page; the token is consumed on first successful use.
Defensive patterns
Strategy: try-catch
Validate before calling
const token = new URL(location.href).searchParams.get('token');
if (!token) throw new Error('Cannot complete Google SSO recovery: token query parameter missing.'); Type guard
function tokenLooksValid(url) {
const t = new URL(url).searchParams.get('token');
return typeof t === 'string' && t.length >= 16 && !/\s/.test(t);
} Try / catch
try {
await completeGoogleSsoRecoverSuccess(token);
} catch (e) {
if (e.message.includes('does not exist or has been deleted')) {
restartSsoRecoverFlow(); // single-use token gone: start over
}
} Prevention
- Use each recovery link exactly once; a second request will always fail.
- Do not refresh or bookmark the success URL.
- Verify tokens are not truncated by email clients or redirect chains.
- Keep the whole flow within the same instance/environment.
When it happens
Trigger: GET /sso/recover/success/google?token=... with a token value matching no record: token consumed by a prior success call, deleted, typo/truncation, or issued by a different instance/database.
Common situations: Refreshing or double-clicking the success URL (second request finds the token already used), replaying an old Google recovery link, switching environments mid-flow.
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.
- $data['error'] (dynamic provider error)
- Invalid provider data. Expected Google settings.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/58262000911bc3c3.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/SsoRecover/src/Controller/Google/GoogleRecoverSuccessController.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)