{"record":{"id":"1456334441ae0f57","repo":"langgenius/dify","slug":"invalid-or-expired-token","errorCode":"invalid_or_expired_token","errorMessage":"The token is invalid or has expired.","messagePattern":"The token is invalid or has expired\\.","errorType":"error_code","errorClass":"InvalidTokenError","httpStatus":400,"severity":"error","filePath":"api/controllers/console/auth/email_register.py","lineNumber":130,"sourceCode":"@console_ns.route(\"/email-register/validity\")\nclass EmailRegisterCheckApi(Resource):\n    @setup_required\n    @email_password_login_enabled\n    @email_register_enabled\n    @console_ns.expect(console_ns.models[EmailRegisterValidityPayload.__name__])\n    @console_ns.response(200, \"Success\", console_ns.models[VerificationTokenResponse.__name__])\n    @model_validate(EmailRegisterValidityPayload)\n    def post(self, req_data: EmailRegisterValidityPayload):\n\n        user_email = req_data.email.lower()\n\n        is_email_register_error_rate_limit = AccountService.is_email_register_error_rate_limit(user_email)\n        if is_email_register_error_rate_limit:\n            raise EmailRegisterLimitError()\n\n        token_data = AccountService.get_email_register_data(req_data.token)\n        if token_data is None:\n            raise InvalidTokenError()\n\n        token_email = token_data.get(\"email\")\n        normalized_token_email = token_email.lower() if isinstance(token_email, str) else token_email\n\n        if user_email != normalized_token_email:\n            raise InvalidEmailError()\n\n        if req_data.code != token_data.get(\"code\"):\n            AccountService.add_email_register_error_rate_limit(user_email)\n            raise EmailCodeError()\n\n        # Verified, revoke the first token\n        AccountService.revoke_email_register_token(req_data.token)\n\n        # Refresh token data by generating a new token\n        _, new_token = AccountService.generate_email_register_token(\n            user_email, code=req_data.code, additional_data={\"phase\": \"register\"}\n        )","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/auth/email_register.py#L112-L148","documentation":"Raised by InvalidTokenError in EmailRegisterCheckApi.post when AccountService.get_email_register_data(req_data.token) returns None. The token is the JWT-style handle returned by the email-send step; None means it is missing, malformed, revoked, or past its TTL. This is the canonical 'your link is stale' signal during the two-phase register flow.","triggerScenarios":"POST /console/api/email-register/validity where req_data.token is unknown to the store, was already consumed by revoke_email_register_token, or has expired. Also fires if the client fabricates or truncates the token.","commonSituations":"User clicks an old registration link after the token TTL elapsed; user refreshed the registration page after the token was revoked; client lost the token from local state and substituted a placeholder; clock skew between issuer and verifier.","solutions":["Restart the registration flow at /email-register/email-send to obtain a fresh token.","Ensure the client forwards the exact token string from the email link without trimming or URL-decoding twice.","Check that the registration token TTL configured on the server is long enough for your email delivery latency.","Verify the client is hitting the same environment (same Dify instance) that issued the token."],"exampleFix":"// before: reuse a token stored days ago\ncheckValidity({ email, token: oldToken, code });\n// after: detect expiry and re-issue\nif (res.code === 'invalid_or_expired_token') {\n  const send = await emailSend({ email });\n  await checkValidity({ email, token: send.token, code: send.code });\n}","handlingStrategy":"try-catch","validationCode":"// Sanity check before calling: ensure token is present and well-formed\nif (!token || token.split('.').length < 2) {\n  await restartRegisterFlow(email);\n  return;\n}","typeGuard":"function isPlausibleToken(t) { return typeof t === 'string' && t.length > 16 && t.includes('.'); }","tryCatchPattern":"try {\n  await checkValidity({ email, token, code });\n} catch (e) {\n  if (e.code === 'invalid_or_expired_token') await restartRegisterFlow(email);\n  else throw e;\n}","preventionTips":["Store the token in sessionStorage immediately after email-send and read from there.","Complete the registration flow within the token TTL.","Never reuse a token that was already consumed by a successful step."],"tags":["auth","registration","token","expired"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}