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 in the URL query is not found as an active, non-expired token; the RecordNotFoundException from SsoAuthenticationTokenGetService::getActiveNotExpiredOrFail is wrapped in this BadRequestException by the OAuth2 recover-success controller.
Solutions
- Restart the SSO recovery flow to obtain a new token and use the fresh link once only.
- Check the token parameter for truncation or encoding issues in the URL.
- Ensure the request goes to the same passbolt instance that issued the token.
- Do not refresh or re-open the success URL after it has completed; the token is single-use.
Defensive patterns
Strategy: try-catch
Validate before calling
const token = new URLSearchParams(window.location.search).get('token');
if (!token || /\s/.test(token)) console.warn('SSO recover token missing or malformed; restart the flow.'); Type guard
function hasToken(url) {
const t = new URL(url, window.location.origin).searchParams.get('token');
return typeof t === 'string' && t.length >= 16;
} Try / catch
try {
await completeOauth2SsoRecoverSuccess(token);
} catch (e) {
if (e.message.includes('does not exist or has been deleted')) {
restartSsoRecoverFlow(); // token single-use; get a new one
}
} Prevention
- Never reuse or refresh the success URL; the token is consumed on first use.
- Verify tokens survive redirect chains intact (no truncation).
- Keep the recovery flow within one environment.
- If a flow fails, restart from the recover-login endpoint rather than retrying the same token.
When it happens
Trigger: GET /sso/recover/success?token=... where the token matches no active record: already consumed by a previous success request, deleted, mistyped/truncated, or issued by another environment.
Common situations: Double-submission or refresh of the success page after the single-use token was consumed; replaying an expired recovery link; migrating between instances mid-recovery.
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.
- AccessToken should be an instance of BaseIdToken class.
- Cannot parse JWKS endpoint response.
- $data['error'] (dynamic provider error)
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/98b4515fe7e45b2b.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/SsoRecover/src/Controller/OAuth2/OAuth2RecoverSuccessController.php:54
$this->Authentication->allowUnauthenticated(['ssoRecoverSuccess']);
}
/**
* @return void
*/
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)