Mintplex-Labs/anything-llm · error
Token expired.
Error message
Token expired.
What it means
validate() found the token row but its expiresAt is earlier than the current time (compared against new Date()), so the token is expired and no session JWT is minted. Temporary auth tokens are intentionally short-lived.
Solutions
- Issue a new temporary auth token and use it promptly
- Regenerate the token close to the moment of delivery, not long before
- Verify server time is correct (NTP) so expiresAt comparisons are accurate
- Surface a clear 'link expired, request a new one' UX instead of a raw error
Example fix
// before
// generating a token far in advance of the email actually being sent
const link = buildLink(token); // token may expire before user clicks
// after
// generate at send time with a comfortable window
const { token } = await TemporaryAuthToken.create(user.id, hoursFromNow(24));
const link = buildLink(token); Defensive patterns
Strategy: try-catch
Validate before calling
null // the expiry state lives server-side in temporary_auth_tokens.expiresAt; // callers cannot reliably pre-check it - handle via the returned error field
Try / catch
const { sessionToken, error } = await TemporaryAuthToken.validate(publicToken);
if (error === 'Token expired.') {
// transparently re-issue and resend the magic link, then stop this attempt
const fresh = await issueNewTemporaryAuthToken(user.id);
return res.status(401).json({ error: 'Link expired. A new one has been sent.', reissued: true });
} Prevention
- Generate tokens at send time with a window comfortable for real delivery and reading
- Keep server clocks NTP-synced so expiresAt comparisons are trustworthy
- Design the UX around expiry: 'request a new link' beats showing a raw error
When it happens
Trigger: Opening a magic link after the expiry window elapsed; server clock set ahead of the token-creation clock; tokens created long ago and reused; delayed email delivery pushing the click past expiry.
Common situations: Users leaving login links in their inbox overnight; scheduled emails sent with tokens generated earlier in the pipeline; container clocks drifting after host suspension.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid token.
- Public token is required to validate a temporary auth token.
- Device not approved
- Device not found
- Device token is required
AI-assisted analysis of Mintplex-Labs/anything-llm@a145d4d87d (2026-08-18).
Data as JSON: /api/errors/8e8bf68293124c01.
Report an issue: GitHub.
Appendix: source
Thrown at server/models/temporaryAuthToken.js:83
* to be set in the browser localStorage for authentication.
* @param {string} publicToken - the token to validate against
* @returns {Promise<{sessionToken: string|null, token: import("@prisma/client").temporary_auth_tokens & {user: import("@prisma/client").users} | null, error: string | null}>}
*/
validate: async function (publicToken = "") {
/** @type {import("@prisma/client").temporary_auth_tokens & {user: import("@prisma/client").users} | undefined | null} **/
let token;
try {
if (!publicToken)
throw new Error(
"Public token is required to validate a temporary auth token."
);
token = await prisma.temporary_auth_tokens.findUnique({
where: { token: String(publicToken) },
include: { user: true },
});
if (!token) throw new Error("Invalid token.");
if (token.expiresAt < new Date()) throw new Error("Token expired.");
if (token.user.suspended) throw new Error("User account suspended.");
// Create a new session token for the user valid for 30 days
const sessionToken = makeJWT(
{ id: token.user.id, username: token.user.username },
process.env.JWT_EXPIRY
);
return { sessionToken, token, error: null };
} catch (error) {
console.error("FAILED TO VALIDATE TEMPORARY AUTH TOKEN.", error.message);
return { sessionToken: null, token: null, error: error.message };
} finally {
// Delete the token after it has been used under all circumstances if it was retrieved
if (token)
await prisma.temporary_auth_tokens.delete({ where: { id: token.id } });
}
},View on GitHub (pinned to a145d4d87d)