lobehub/lobehub · error · TRPCError
FORBIDDEN
FORBIDDEN
Error message
Workspace API Key creation is restricted to admins
What it means
Thrown by createApiKey when the workspace's API-key-creation policy is 'admins_only' and the caller's workspaceRole is neither 'owner' nor 'admin'. It is a role-gate that runs after the workspace feature flag (canUseWorkspaceApiKeys) but before the key is actually created. The check reads ctx.workspaceRole, which the cloud workspace-auth middleware injects and the OSS stub leaves absent.
Source
Thrown at apps/server/src/routers/lambda/apiKey.ts:96
expiresAt: z.date().nullish(),
name: z.string(),
// `undefined`/`null` = full access; entries must come from the
// catalog — unknown scope strings are rejected.
scopes: apiKeyScopesSchema,
}),
)
.mutation(async ({ input, ctx }) => {
if (ctx.workspaceId) {
if (!(await canUseWorkspaceApiKeys(ctx.workspaceId))) {
throw new TRPCError({
code: 'PRECONDITION_FAILED',
message: 'Workspace API Key access is not available',
});
}
const memberCreation = await ctx.workspaceModel.getApiKeyMemberCreation(ctx.workspaceId);
if (memberCreation === 'admins_only' && !isWorkspaceAdmin(ctx)) {
throw new TRPCError({
code: 'FORBIDDEN',
message: 'Workspace API Key creation is restricted to admins',
});
}
}
const scopes = normalizeScopes(input.scopes);
const result = await ctx.apiKeyModel.create({ ...input, scopes });
await recordApiKeyAudit(ctx, {
action: 'api_key.created',
metadata: { expiresAt: result.expiresAt, name: result.name, scopes: result.scopes ?? null },
resourceId: result.id,
});
return result;
}),
deleteAllApiKeys: apiKeyProcedureView on GitHub (pinned to 10f24d7ade)
Solutions
- Have a workspace owner/admin create the key, or have an admin escalate the caller's workspaceRole to 'admin'.
- Change the workspace setting getApiKeyMemberCreation from 'admins_only' to 'members' (or 'open') via workspace config if the policy is too strict.
- If the caller is actually an admin, verify ctx.workspaceRole is being injected correctly by the workspace-auth middleware — an absent/undefined field fails the check.
- Call the endpoint outside a workspace context (no ctx.workspaceId) to bypass the workspace gate entirely in personal/OSS mode.
Example fix
// before: member calls createApiKey in admins_only workspace -> FORBIDDEN
// after: an admin creates it, or workspace policy is relaxed
const memberCreation = await workspaceModel.getApiKeyMemberCreation(wsId);
if (memberCreation === 'admins_only' && !isWorkspaceAdmin(ctx)) {
// surface a UI hint: 'Ask a workspace admin to create this key'
throw new Error('Ask an admin');
} Defensive patterns
Strategy: validation
Validate before calling
// Before calling createApiKey, check the caller's role and workspace policy
const canCreate = !workspaceId ||
(await workspaceModel.getApiKeyMemberCreation(workspaceId)) !== 'admins_only' ||
isWorkspaceAdmin({ workspaceRole });
if (!canCreate) {
throw new Error('Ask a workspace admin to create this key');
}
await apiKeyRouter.createApiKey.mutate({ name, scopes, expiresAt }); Type guard
const isWorkspaceAdminRole = (
ctx: { workspaceRole?: string }
): ctx is { workspaceRole: 'owner' | 'admin' } =>
ctx.workspaceRole === 'owner' || ctx.workspaceRole === 'admin'; Try / catch
try {
await apiKeyRouter.createApiKey.mutate(input);
} catch (e) {
if (e.shape?.data?.code === 'FORBIDDEN' && /admins/.test(e.message)) {
// prompt the user to request admin escalation
} else throw e;
} Prevention
- Surface the workspace's getApiKeyMemberCreation policy in the UI before showing the 'create key' action to non-admins.
- Gate the 'Create API Key' button on the caller's workspaceRole being owner or admin when policy is admins_only.
- Document the admins_only policy effect for workspace members onboarding.
When it happens
Trigger: Calling apiKeyRouter.createApiKey while ctx.workspaceId is set, the workspace setting getApiKeyMemberCreation() returns 'admins_only', and ctx.workspaceRole is 'member', 'viewer', or undefined (OSS stub). A non-admin member or a viewer attempting to mint a key in a workspace locked down to admins hits this.
Common situations: An enterprise/cloud workspace where an owner restricted API key creation to admins via workspace settings. A member tries to create a personal key through the workspace-scoped endpoint. Also occurs in OSS deployments if the workspace auth stub injects a non-admin role.
Related errors
AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12).
Data as JSON: /api/errors/224589a33d20f23c.
Report an issue: GitHub.