-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Problem
When auth is configured, coreAuthMiddleware authenticates the user and sets user on requestContext (line 278 of helpers.ts). However, it does not set mastra__resourceId, which is required for memory/thread scoping per user.
Currently, there's no first-class way to set mastra__resourceId after auth succeeds because:
checkRouteAuthruns inside the route handler callback, not as separate framework middleware- By the time user-defined middleware runs, the user isn't on
requestContextyet - The only workaround is subclassing the server adapter and overriding
checkRouteAuth— which works but is adapter-specific and feels like a hack
This affects all server adapters (Hono, Express, Next.js, etc.) and is especially painful for Mastra Studio users who want threads/memory scoped to the authenticated user.
Proposed Solution
Add a mapUserToResourceId callback to the server auth config:
const server = new MastraServer({
auth: workosAuth,
mapUserToResourceId: (user) => user.id, // simple case
// or for org-scoped:
// mapUserToResourceId: (user) => `${user.organizationId}:${user.id}`,
});In coreAuthMiddleware, after the user is authenticated and set on requestContext:
requestContext.set('user', user);
// Auto-set resource ID if callback is provided
if (authConfig.mapUserToResourceId) {
const resourceId = authConfig.mapUserToResourceId(user);
if (resourceId) {
requestContext.set(MASTRA_RESOURCE_ID_KEY, resourceId);
}
}Since this lives in the shared coreAuthMiddleware (not in any adapter), it would work across all server adapters automatically.
Why not just default to user.id?
The resource ID isn't always user.id. Common cases where it differs:
- Org-scoped:
${user.organizationId}:${user.id} - Custom claims: Resource ID from a JWT claim or external mapping
- Multi-tenant: Scoped to a tenant ID rather than user ID
- Composite keys: Combination of user + workspace + project
A callback gives consumers full control while keeping the common case simple.
Current Workaround
Subclass the adapter-specific server class and override checkRouteAuth. For example, with the Hono adapter:
import { MastraServer } from '@mastra/hono';
import { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context';
class MyMastraServer extends MastraServer {
protected override async checkRouteAuth(route: any, context: any) {
const result = await super.checkRouteAuth(route, context);
if (!result && context.requestContext) {
const user = context.requestContext.get('user');
if (user?.id) {
context.requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id);
}
}
return result;
}
}Similar overrides would be needed for Express, Next.js, or any other adapter. This works but requires adapter-specific subclassing for something that should be a shared config option.
Related
- Studio auth flow breaks when Studio and API run on different origins/prefixes #13901 (hardcoded
/api/prefix issues affecting Studio with customapiPrefix)