passbolt/passbolt_api · error · BadRequestException

The authentication token has been expired.

Error message

The authentication token has been expired.

What it means

Identical to the OAuth2 variant: thrown by PingOneRecoverSuccessController::ssoRecoverSuccess when the recovery token is found but CustomValidationException indicates it expired (or is inactive), wrapped as BadRequestException. SSO recovery tokens are short-lived by design.

Solutions

  1. Start the SSO recover flow again to generate a fresh token
  2. Complete the provider login and callback promptly
  3. Synchronize server clock via NTP if expiry behaves incorrectly
  4. Increase token expiry configuration only if operationally justified

Example fix

// before
GET /sso/recover/success/pingone?token=<expired>
// after: regenerate
GET /recover/start -> fresh link -> callback within token TTL
Defensive patterns

Strategy: try-catch

Validate before calling

const isExpired = (t) => t?.expires && Date.now() > new Date(t.expires).getTime();
if (isExpired(token)) 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 reaches the PingOne success callback after the TYPE_SSO_RECOVER token's expiry; long delay during provider authentication; clock skew on the server.

Common situations: Slow SSO provider login; user idles on the provider login page past token TTL; bookmarked/replayed link visited later; server time drift.

Understand the failure class

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/SsoRecover/src/Controller/PingOne/PingOneRecoverSuccessController.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)