{"record":{"id":"74112beaaaa57c31","repo":"langfuse/langfuse","slug":"authcheck-error","errorCode":null,"errorMessage":"${authCheck.error}","messagePattern":"\\$\\{authCheck\\.error\\}","errorType":"exception","errorClass":"UnauthorizedError","httpStatus":401,"severity":"error","filePath":"web/src/features/prompts/server/utils/authorizePromptRequest.ts","lineNumber":15,"sourceCode":"import { ApiAuthService } from \"@/src/features/public-api/server/apiAuth\";\nimport { type NextApiRequest } from \"next\";\nimport { UnauthorizedError, ForbiddenError } from \"@langfuse/shared\";\nimport { prisma } from \"@langfuse/shared/src/db\";\nimport {\n  type AuthHeaderValidVerificationResult,\n  redis,\n} from \"@langfuse/shared/src/server\";\n\nexport async function authorizePromptRequestOrThrow(req: NextApiRequest) {\n  const authCheck = await new ApiAuthService(\n    prisma,\n    redis,\n  ).verifyAuthHeaderAndReturnScope(req.headers.authorization);\n  if (!authCheck.validKey) throw new UnauthorizedError(authCheck.error);\n  if (authCheck.scope.accessLevel !== \"project\")\n    throw new ForbiddenError(\n      `Access denied - need to use basic auth with secret key to ${req.method} prompts`,\n    );\n  if (!authCheck.scope.projectId) {\n    throw new ForbiddenError(`No valid projectId found for auth token`);\n  }\n  return authCheck as AuthHeaderValidVerificationResult & {\n    scope: { projectId: string; accessLevel: \"project\" };\n  };\n}\n","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/features/prompts/server/utils/authorizePromptRequest.ts#L1-L27","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the API key pair exists and is active in project settings","Send Authorization: Basic base64(pk:sk) for secret-key endpoints","Check the underlying authCheck.error message for the precise cause","Rotate and re-distribute keys if the old ones were revoked"],"exampleFix":"// before\nfetch(url, { headers: { Authorization: `Bearer ${publicKey}` } });\n// after\nconst creds = Buffer.from(`${publicKey}:${secretKey}`).toString('base64');\nfetch(url, { headers: { Authorization: `Basic ${creds}` } });","handlingStrategy":"try-catch","validationCode":"const token = Buffer.from(`${publicKey}:${secretKey}`).toString('base64');\nif (!publicKey || !secretKey) throw new Error('API keys missing');\nawait fetch(url, { headers: { Authorization: `Basic ${token}` } });","typeGuard":null,"tryCatchPattern":"try {\n  await api.prompts.list();\n} catch (e) {\n  if (e.status === 401) { /* key invalid: verify/rotate keys in project settings */ }\n  if (e.status === 403) { /* scope wrong: use project secret key */ }\n}","preventionTips":["Store pk/sk pairs together in a secrets manager","Basic-auth encode as base64(pk:sk), never send raw","Rotate keys atomically across all consumers"],"tags":["auth","api-key","unauthorized","public-api"],"backgroundTag":"invalid-api-key","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}