mastra-ai/mastra · critical

JWT auth secret is required

Error message

JWT auth secret is required

What it means

MastraJwtAuth's constructor resolves its signing/verification secret from options.secret, falling back to the JWT_AUTH_SECRET environment variable, and defaults to an empty string. If no non-empty secret is found it immediately throws 'JWT auth secret is required', because a JWT auth provider is unusable and unsafe without a secret.

Source

Thrown at packages/auth/src/jwt.ts:41

  return {
    id,
    email: str(payload.email),
    name: str(payload.name),
    avatarUrl: str(payload.avatarUrl) || str(payload.avatar_url) || str(payload.picture),
  };
}

export class MastraJwtAuth extends MastraAuthProvider<JwtUser> implements IUserProvider {
  protected secret: string;
  private mapUser: (payload: JwtUser) => User | null;

  constructor(options?: MastraJwtAuthOptions) {
    super({ name: options?.name ?? 'jwt' });

    this.secret = options?.secret ?? process.env.JWT_AUTH_SECRET ?? '';

    if (!this.secret) {
      throw new Error('JWT auth secret is required');
    }

    this.mapUser = options?.mapUser ?? defaultMapUser;
    this.registerOptions(options);
  }

  async authenticateToken(token: string): Promise<JwtUser> {
    return jwt.verify(token, this.secret) as JwtUser;
  }

  async authorizeUser(user: JwtUser) {
    return !!user;
  }

  async getCurrentUser(request: Request): Promise<User | null> {
    const authHeader = request.headers.get('authorization');
    const token = authHeader?.toLowerCase().startsWith('bearer ') ? authHeader.slice(7).trim() : null;
    if (!token) return null;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Set the JWT_AUTH_SECRET environment variable (e.g. in .env or the deployment's secret/config settings)
  2. Or pass the secret explicitly: new MastraJwtAuth({ secret: '<your-secret>' })
  3. Ensure dotenv/config loading runs before the MastraJwtAuth constructor executes
  4. Generate a strong secret if missing, e.g. `openssl rand -base64 32`

Example fix

// before
const auth = new MastraJwtAuth();
// after
const auth = new MastraJwtAuth({ secret: process.env.JWT_AUTH_SECRET }); // with JWT_AUTH_SECRET set in env
Defensive patterns

Strategy: validation

Validate before calling

const secret = options?.secret ?? process.env.JWT_AUTH_SECRET;
if (!secret) {
  throw new Error('JWT_AUTH_SECRET is not set. Generate one with: openssl rand -base64 32');
}
const auth = new MastraJwtAuth({ secret });

Type guard

export function hasJwtSecret(opts?: { secret?: string }): opts is { secret: string } & NonNullable<Parameters<typeof MastraJwtAuth>[0]> {
  return typeof opts?.secret === 'string' && opts.secret.length > 0 || !!process.env.JWT_AUTH_SECRET;
}

Try / catch

let auth;
try {
  auth = new MastraJwtAuth({ secret: process.env.JWT_AUTH_SECRET });
} catch (e) {
  if (e instanceof Error && e.message === 'JWT auth secret is required') {
    console.error('Set JWT_AUTH_SECRET in your environment before booting the server');
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: new MastraJwtAuth() with no options.secret while process.env.JWT_AUTH_SECRET is unset or empty string; also occurs if the env var is loaded after construction (e.g. dotenv initialized too late) or not loaded in the deployment environment at all.

Common situations: Forgetting JWT_AUTH_SECRET in .env, env vars not propagated to the deployed service (Docker/Cloud runtimes, CI), dotenv not called before server construction, or a typo'd variable name.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/6570eaabc9bf70cd. Report an issue: GitHub.