{"record":{"id":"9610f354dfa2baf1","repo":"passbolt/passbolt_api","slug":"the-authentication-token-has-been-expired-9610f3","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/PingOne/PingOneRecoverSuccessController.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/PingOne/PingOneRecoverSuccessController.php#L42-L74","documentation":"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.","triggerScenarios":"User reaches the PingOne success callback after the TYPE_SSO_RECOVER token's expiry; long delay during provider authentication; clock skew on the server.","commonSituations":"Slow SSO provider login; user idles on the provider login page past token TTL; bookmarked/replayed link visited later; server time drift.","solutions":["Start the SSO recover flow again to generate a fresh token","Complete the provider login and callback promptly","Synchronize server clock via NTP if expiry behaves incorrectly","Increase token expiry configuration only if operationally justified"],"exampleFix":"// before\nGET /sso/recover/success/pingone?token=<expired>\n// after: regenerate\nGET /recover/start -> fresh link -> callback within token TTL","handlingStrategy":"try-catch","validationCode":"const isExpired = (t) => t?.expires && Date.now() > new Date(t.expires).getTime();\nif (isExpired(token)) 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":["Avoid long idles on the SSO provider login page","Regenerate the token if the flow stalls","Keep server clocks NTP-synchronized","Document the token TTL for support teams"],"tags":["sso","auth-token","expired-token","pingone"],"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"}