Mintplex-Labs/anything-llm · error

Invalid token.

Error message

Invalid token.

What it means

validate() ran a findUnique on temporary_auth_tokens for the given token string and found no row. The token never existed in this database, was revoked or deleted, or belongs to a different instance. Note the token column is matched exactly - truncation or whitespace breaks the lookup.

Solutions

  1. Generate and share a fresh temporary auth token
  2. Copy the token completely and URL-decode it before validating
  3. Confirm the client and server hit the same database/instance
  4. If tokens are single-use by policy, treat consumption as expected and re-issue

Example fix

// before
TemporaryAuthToken.validate(token.trimEnd() + '='); // accidental mutation -> Invalid token.

// after
TemporaryAuthToken.validate(decodeURIComponent(token).trim());
Defensive patterns

Strategy: try-catch

Validate before calling

const publicToken = decodeURIComponent(String(rawToken ?? '')).trim();
if (publicToken.length === 0) {
  return res.status(400).json({ error: 'token is required' });
}

Try / catch

const { sessionToken, error } = await TemporaryAuthToken.validate(publicToken);
if (error === 'Invalid token.') {
  // unknown/revoked token: respond 401 and offer to generate a new link
  return res.status(401).json({ error: 'Invalid login link. Request a new one.' });
}
if (error) return res.status(401).json({ error });

Prevention

When it happens

Trigger: A typo'd or truncated token (copy missing characters, URL-decoding issues); the token was deleted after use or by an admin; the database was reset while the link was still being shared; '+' or special characters mangled by query parsing.

Common situations: Magic-link emails clipped by mail clients; tokens copied with surrounding whitespace or percent-encoding intact; load-balanced instances pointing at different databases.

Understand the failure class

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@a145d4d87d (2026-08-18). Data as JSON: /api/errors/37c1e322b060a5f4. Report an issue: GitHub.

Appendix: source

Thrown at server/models/temporaryAuthToken.js:82

   * Validates a temporary auth token and returns the session token
   * 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)