{"record":{"id":"9c2d74b19b656514","repo":"passbolt/passbolt_api","slug":"the-authentication-token-has-been-expired-9c2d74","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/Google/GoogleRecoverSuccessController.php","lineNumber":62,"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":44,"sourceCodeEnd":76,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/SsoRecover/src/Controller/Google/GoogleRecoverSuccessController.php#L44-L76","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Start the recovery again and complete the Google OAuth redirect promptly within the token lifetime.","Do not pause between initiating recovery and completing the provider callback.","Ensure server time is synchronized (NTP) and timezone configuration is correct.","Review SSO token expiry settings if the lifetime is too short for your users."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Guard against stale links: warn if the recovery link is older than the token TTL\nif (Date.now() - linkCreatedAtMs > TOKEN_TTL_MINUTES * 60000) {\n  promptUserToRestartRecovery();\n}","typeGuard":null,"tryCatchPattern":"try {\n  await completeGoogleSsoRecoverSuccess(token);\n} catch (e) {\n  if (e.message.includes('has been expired')) {\n    await restartSsoRecoverFlow();\n  }\n}","preventionTips":["Complete the Google sign-in immediately after starting recovery.","Synchronize server time (NTP) so tokens do not expire early.","Avoid idle tabs during the recovery flow.","Adjust SSO token lifetime settings if the default is too short."],"tags":["sso","authentication-token","token-expired","google"],"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"}