{"record":{"id":"3f246ee6fd12fd55","repo":"passbolt/passbolt_api","slug":"the-authentication-token-has-been-expired-3f246e","errorCode":null,"errorMessage":"The authentication token has been expired.","messagePattern":"The authentication token has been expired\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/SsoRecover/src/Controller/OAuth2/OAuth2RecoverSuccessController.php","lineNumber":60,"sourceCode":"    public function ssoRecoverSuccess(): void\n    {\n        if ($this->request->is('json')) {\n            throw new BadRequestException(__('Ajax/Json request not supported.'));\n        }\n\n        $this->User->assertNotLoggedIn();\n        $token = $this->getTokenFromUrlQuery();\n\n        try {\n            (new SsoAuthenticationTokenGetService())->getActiveNotExpiredOrFail($token, SsoState::TYPE_SSO_RECOVER);\n        } catch (RecordNotFoundException $e) {\n            throw new BadRequestException(\n                __('The authentication token does not exist or has been deleted.'),\n                null,\n                $e\n            );\n        } catch (CustomValidationException $e) {\n            throw new BadRequestException(\n                __('The authentication token has been expired.'),\n                null,\n                $e\n            );\n        }\n\n        $this->viewBuilder()\n            ->setTheme('Passbolt/Sso')\n            ->setLayout('default')\n            ->setTemplatePath('success')\n            ->setTemplate('stage3');\n    }\n}\n","sourceCodeStart":42,"sourceCodeEnd":74,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/SsoRecover/src/Controller/OAuth2/OAuth2RecoverSuccessController.php#L42-L74","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Restart the SSO recovery flow from /recover to generate a fresh token","Complete the success step promptly after the provider redirects back","Check server timezone/clock (NTP) if tokens seem to expire too early","Verify no proxy/cache is replaying an old callback URL"],"exampleFix":"// before (stale link reuse)\nGET /sso/recover/success?token=<expired-token>\n// after\nGET /recover/start  ->  new email/link  ->  GET /sso/recover/success?token=<fresh-token>","handlingStrategy":"try-catch","validationCode":"const isLikelyExpired = (expires) => Date.now() > new Date(expires).getTime();\nif (isLikelyExpired(token.expires)) await restartRecoverFlow();","typeGuard":null,"tryCatchPattern":"try {\n  await completeSsoRecoverSuccess(token);\n} catch (e) {\n  if (e.message.includes('expired')) await restartRecoverFlow();\n  else throw e;\n}","preventionTips":["Complete the recovery flow immediately after receiving the link","Never bookmark or reuse recovery links","Synchronize server clocks with NTP","Monitor token TTL vs. typical provider login duration"],"tags":["sso","auth-token","expired-token","bad-request"],"backgroundTag":"jwt-token-expired","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}