{"record":{"id":"c6e6db3abc45a879","repo":"passbolt/passbolt_api","slug":"the-authentication-token-has-been-expired","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/Azure/AzureRecoverSuccessController.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/Azure/AzureRecoverSuccessController.php#L44-L76","documentation":"Thrown when the SSO recover token exists but the SsoAuthenticationTokenGetService determined it is no longer active/valid (CustomValidationException from getActiveNotExpiredOrFail, i.e. expired or in an inactive state). The controller maps that to this BadRequestException.","triggerScenarios":"GET /sso/recover/success/azure?token=... where the token's created/expiry timestamp is past the SSO authentication token lifetime, or the token was deactivated after a failed/completed recover attempt.","commonSituations":"User waits too long between starting the SSO recovery and completing the OAuth redirect (token TTL elapsed), leaves the recovery tab open overnight, or the server clock/timezone is misconfigured causing premature expiry.","solutions":["Restart the recover flow to generate a new token and complete the OAuth redirect promptly within the token lifetime.","Complete the flow in a single session without long pauses between the login start and provider callback.","Verify server clocks are synchronized (NTP) and the app timezone settings are correct.","If tokens expire too quickly for your users, review the SSO token expiry configuration."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Check token age client-side if the issue time is known\nconst elapsedMin = (Date.now() - tokenIssuedAtMs) / 60000;\nif (elapsedMin > TOKEN_TTL_MINUTES) await restartSsoRecoverFlow();","typeGuard":null,"tryCatchPattern":"try {\n  await completeSsoRecoverSuccess(token);\n} catch (e) {\n  if (e.message.includes('has been expired')) {\n    await restartSsoRecoverFlow(); // obtain a fresh token\n  }\n}","preventionTips":["Complete the OAuth redirect promptly after starting recovery; the token has a short TTL.","Synchronize server clocks with NTP to avoid premature expiry.","Do not leave recovery links/tabs idle before completing the flow.","Review SSO token expiry configuration if it is too short for your users."],"tags":["sso","authentication-token","token-expired","recover"],"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"}