langfuse/langfuse · error · ForbiddenError

Access denied - need to use basic auth with secret key to ${

Error message

Access denied - need to use basic auth with secret key to ${req.method} prompts

What it means

ForbiddenError thrown when the auth key's scope.accessLevel is not 'project': prompt API operations require a project-scoped secret key (basic auth), not a public or organization-scoped key.

Source

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

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. Use the project's secret key (sk-) with Basic auth for prompt endpoints
  2. Confirm accessLevel is 'project' in the key's settings
  3. Separate ingestion keys from management keys in your configuration

Example fix

// before
Authorization: Basic base64(publicApiKey:)
// after
Authorization: Basic base64(publicKey:secretKey)
Defensive patterns

Strategy: validation

Validate before calling

// Only use project secret keys for prompt management
if (!secretKey.startsWith('sk-')) throw new Error('Prompt APIs need a project secret key');

Type guard

const isProjectSecretKey = (k: string) => k.startsWith('sk-');

Try / catch

try {
  await api.prompts.create(body);
} catch (e) {
  if (e.status === 403 && /basic auth with secret key/.test(e.message)) {
    // switch from public/bearer to project secret key
  }
}

Prevention

When it happens

Trigger: Calling GET/POST/etc. on /api/public/prompts with a public key (publicApiKey access level) or any non-project scope, where req.method is reflected in the message.

Common situations: Using a public-only key (e.g., tracing ingestion key) for prompt management; mixing up pk-/sk- prefixed keys; scripts built for ingestion reused for prompt CRUD.

Understand the failure class

Related errors


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