passbolt/passbolt_api · error · BadRequestException

The authentication token has been expired.

Error message

The authentication token has been expired.

What it means

Thrown when the Google SSO recover token exists but getActiveNotExpiredOrFail raises CustomValidationException because the token is expired or inactive; the controller converts it to this BadRequestException. It signals the recovery session window has lapsed.

Solutions

  1. Start the recovery again and complete the Google OAuth redirect promptly within the token lifetime.
  2. Do not pause between initiating recovery and completing the provider callback.
  3. Ensure server time is synchronized (NTP) and timezone configuration is correct.
  4. Review SSO token expiry settings if the lifetime is too short for your users.
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard against stale links: warn if the recovery link is older than the token TTL
if (Date.now() - linkCreatedAtMs > TOKEN_TTL_MINUTES * 60000) {
  promptUserToRestartRecovery();
}

Try / catch

try {
  await completeGoogleSsoRecoverSuccess(token);
} catch (e) {
  if (e.message.includes('has been expired')) {
    await restartSsoRecoverFlow();
  }
}

Prevention

When it happens

Trigger: GET /sso/recover/success/google?token=... where the token's validity period has passed between the recover-login initiation and the Google OAuth callback, or the token was deactivated.

Common situations: User delays completing the Google sign-in (token TTL expires), leaves the recovery email link open too long before using it, or server clock skew causes early expiry.

Understand the failure class

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/SsoRecover/src/Controller/Google/GoogleRecoverSuccessController.php:62

    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)