passbolt/passbolt_api · error · BadRequestException

The authentication token has been expired.

Error message

The authentication token has been expired.

What it means

Thrown by OAuth2RecoverSuccessController::ssoRecoverSuccess when the SSO recovery authentication token exists but has failed validation because it expired or is no longer active. The underlying CustomValidationException from SsoAuthenticationTokenGetService::getActiveNotExpiredOrFail is wrapped in a BadRequestException with this user-facing message. Passbolt SSO recovery tokens have a short lifetime for security; once expired the recovery flow must be restarted.

Solutions

  1. Restart the SSO recovery flow from /recover to generate a fresh token
  2. Complete the success step promptly after the provider redirects back
  3. Check server timezone/clock (NTP) if tokens seem to expire too early
  4. Verify no proxy/cache is replaying an old callback URL

Example fix

// before (stale link reuse)
GET /sso/recover/success?token=<expired-token>
// after
GET /recover/start  ->  new email/link  ->  GET /sso/recover/success?token=<fresh-token>
Defensive patterns

Strategy: try-catch

Validate before calling

const isLikelyExpired = (expires) => Date.now() > new Date(expires).getTime();
if (isLikelyExpired(token.expires)) await restartRecoverFlow();

Try / catch

try {
  await completeSsoRecoverSuccess(token);
} catch (e) {
  if (e.message.includes('expired')) await restartRecoverFlow();
  else throw e;
}

Prevention

When it happens

Trigger: User clicks an SSO recover-success link after the sso auth token (TYPE_SSO_RECOVER) has passed its expiry; user delays between the SSO provider callback and the success request; server clock skew makes the token appear expired.

Common situations: User bookmarks the recovery link and revisits it days later; email delivery delay; user completes the SSO provider login slowly and the token TTL lapses before the callback.

Understand the failure class

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/3f246ee6fd12fd55. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/SsoRecover/src/Controller/OAuth2/OAuth2RecoverSuccessController.php:60

    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)