mastra-ai/mastra · error · HTTPException
FGA authorization denied: authenticated user is required
Error message
FGA authorization denied: authenticated user is required
What it means
When a Fine-Grained Authorization (FGA) provider is configured, enforceThreadAccess requires an authenticated user object in requestContext to evaluate thread permissions. If no user is present (auth disabled or hook did not populate it), the check cannot run, so it fails closed with this 403 rather than granting access.
Source
Thrown at packages/server/src/server/handlers/utils.ts:153
permission = MastraFGAPermissions.MEMORY_READ,
}: {
mastra: any;
requestContext?: RequestContext;
threadId: string;
thread?: { resourceId?: string | null } | null;
effectiveResourceId?: string;
permission?: MastraFGAPermissionInput;
}): Promise<void> {
await validateThreadOwnership(thread, effectiveResourceId);
const fgaProvider = mastra?.getServer?.()?.fga;
if (!fgaProvider) {
return;
}
const user = requestContext?.get('user');
if (!user || typeof user !== 'object') {
throw new HTTPException(403, { message: 'FGA authorization denied: authenticated user is required' });
}
await MastraMemory.checkThreadFGA({
mastra,
user: user as { id: string; [key: string]: unknown },
threadId,
resourceId: thread?.resourceId ?? effectiveResourceId,
requestContext,
permission,
});
}
/**
* Validates that a workflow run belongs to the specified resourceId.
* Throws 403 if the run exists but belongs to a different resource.
*/
export async function validateRunOwnership(
run: { resourceId?: string | null } | null | undefined,View on GitHub (pinned to 75dd419e61)
Solutions
- Enable and correctly configure server authentication so a user object is attached to requestContext for every request.
- In custom auth, ensure you call requestContext.set('user', { id, ... }) after validating credentials.
- Use an authenticated client (valid token/credentials) when calling FGA-protected routes.
- Temporarily disable the FGA provider in non-production if unauthenticated internal calls are required.
Example fix
// before
// custom auth verifies token but never sets user
if (token) next();
// after
const user = await verifyToken(token);
requestContext.set('user', { id: user.sub, email: user.email });
next(); Defensive patterns
Strategy: validation
Validate before calling
function requireAuthenticatedUser(requestContext: { get: (k: string) => unknown }): asserts requestContext is { get: (k: 'user') => { id: string } } {
const user = requestContext.get('user');
if (!user || typeof user !== 'object' || typeof (user as any).id !== 'string') {
throw new Error('FGA-protected routes require an authenticated user attached to requestContext');
}
} Type guard
function hasUser(ctx: { get: (k: string) => unknown }): boolean {
const u = ctx.get('user');
return !!u && typeof u === 'object' && typeof (u as any).id === 'string';
} Try / catch
try {
const res = await fetch('/api/agents/assistant/generate', { method: 'POST', headers: authHeaders, body: JSON.stringify(payload) });
if (res.status === 403 && (await res.text()).includes('FGA authorization denied')) {
throw new Error('Ensure server auth is enabled and the user is attached to requestContext when FGA is configured');
}
return await res.json();
} catch (e) { throw e; } Prevention
- If you enable an FGA provider, always enable server auth with it.
- In custom auth plugins, call requestContext.set('user', { id, ... }) after token validation.
- Use authenticated clients for all calls to FGA-protected routes.
- Add an integration test asserting the user is present in requestContext.
When it happens
Trigger: Calling generate/stream/list-suspended/resume routes on a Mastra server with an FGA provider configured, where requestContext has no `user` object — typically because authentication is disabled or the auth hook failed to attach the user.
Common situations: Enabling FGA (e.g. OpenFGA/SpiceDB integration) while leaving server auth disabled; a custom auth plugin that validates tokens but never sets requestContext.set('user', ...); calling routes with an unauthenticated internal service client.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- You need the admin role in this organization to manage datab
- FGA denied for tool '${resourceId}'
- Access denied: durable run belongs to a different resource
- Admin access required
- Access denied: unable to verify message thread access
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2c999f515437cdae.
Report an issue: GitHub.