langfuse/langfuse · error · UnauthorizedError

${authCheck.error}

Error message

${authCheck.error}

What it means

UnauthorizedError from authorizePromptRequestOrThrow when ApiAuthService.verifyAuthHeaderAndReturnScope reports an invalid key; the message is the underlying authCheck.error string (e.g., 'Invalid credentials'). Used by the public prompt API endpoints to gate requests.

Source

Thrown at web/src/features/prompts/server/utils/authorizePromptRequest.ts:15

import { ApiAuthService } from "@/src/features/public-api/server/apiAuth";
import { type NextApiRequest } from "next";
import { UnauthorizedError, ForbiddenError } from "@langfuse/shared";
import { prisma } from "@langfuse/shared/src/db";
import {
  type AuthHeaderValidVerificationResult,
  redis,
} from "@langfuse/shared/src/server";

export async function authorizePromptRequestOrThrow(req: NextApiRequest) {
  const authCheck = await new ApiAuthService(
    prisma,
    redis,
  ).verifyAuthHeaderAndReturnScope(req.headers.authorization);
  if (!authCheck.validKey) throw new UnauthorizedError(authCheck.error);
  if (authCheck.scope.accessLevel !== "project")
    throw new ForbiddenError(
      `Access denied - need to use basic auth with secret key to ${req.method} prompts`,
    );
  if (!authCheck.scope.projectId) {
    throw new ForbiddenError(`No valid projectId found for auth token`);
  }
  return authCheck as AuthHeaderValidVerificationResult & {
    scope: { projectId: string; accessLevel: "project" };
  };
}

View on GitHub (pinned to 59d92c7cf3)

Solutions

  1. Verify the API key pair exists and is active in project settings
  2. Send Authorization: Basic base64(pk:sk) for secret-key endpoints
  3. Check the underlying authCheck.error message for the precise cause
  4. Rotate and re-distribute keys if the old ones were revoked

Example fix

// before
fetch(url, { headers: { Authorization: `Bearer ${publicKey}` } });
// after
const creds = Buffer.from(`${publicKey}:${secretKey}`).toString('base64');
fetch(url, { headers: { Authorization: `Basic ${creds}` } });
Defensive patterns

Strategy: try-catch

Validate before calling

const token = Buffer.from(`${publicKey}:${secretKey}`).toString('base64');
if (!publicKey || !secretKey) throw new Error('API keys missing');
await fetch(url, { headers: { Authorization: `Basic ${token}` } });

Try / catch

try {
  await api.prompts.list();
} catch (e) {
  if (e.status === 401) { /* key invalid: verify/rotate keys in project settings */ }
  if (e.status === 403) { /* scope wrong: use project secret key */ }
}

Prevention

When it happens

Trigger: Hitting a public /api/public/prompts* endpoint with a missing, malformed, revoked, or non-existent API key in the Authorization header, causing validKey to be false.

Common situations: Wrong or rotated API keys in .env; Basic auth header not base64-encoded correctly; keys deleted after a security rotation; using org keys where project keys are required.

Related errors


AI-assisted analysis of langfuse/langfuse@59d92c7cf3 (2026-08-27). Data as JSON: /api/errors/74112beaaaa57c31. Report an issue: GitHub.