Middleware
Trust: ★★★☆☆ (0.90) · 0 validations · developer_reference
Published: 2026-05-10 · Source: crawler_authoritative
Tình huống
Guide for configuring custom middleware functions in Mastra servers for authentication, logging, CORS, and request context injection.
Insight
Mastra servers execute custom middleware functions before or after API route handlers. Middleware receives the Hono Context (c) and a next function. If middleware returns a Response, the request is short-circuited. Calling next() continues to the next middleware or route handler. Middleware can be registered globally in the Mastra server config under server.middleware as an array of handler objects or functions. Each middleware handler can optionally specify a path pattern (e.g., ‘/api/*’) to limit execution to matching routes. Middleware can also be attached to individual routes via the registerApiRoute middleware option. The RequestContext object can be populated dynamically in middleware by extracting request headers like CF-IPCountry. Authorization uses the mapUserToResourceId callback which is called after successful authentication and sets MASTRA_RESOURCE_ID_KEY on the request context. The resource ID can be a user ID, org-scoped value, tenant ID from JWT claims, or composite key. Setting this value automatically scopes memory/threads to the authenticated user and validates thread access (403 for other users’ resources). For complex scenarios, MASTRA_RESOURCE_ID_KEY can be set directly in middleware using getAuthenticatedUser() helper. MASTRA_THREAD_ID_KEY can also be set to override client-provided thread IDs.
Hành động
To register global middleware, add a middleware array to the Mastra server config with handler functions that receive (c, next). To apply middleware to a specific route, pass the middleware option to registerApiRoute with an array of handler functions. For path-scoped middleware, use the { handler, path } object format. For authentication, check for Authorization header and return 401 if missing. Call await next() to continue processing. For user isolation, configure mapUserToResourceId in auth config to return a string ID from the authenticated user object. For advanced middleware that needs the authenticated user, use getAuthenticatedUser() helper with mastra instance, token, and request. Set requestContext.set(MASTRA_RESOURCE_ID_KEY, value) to scope resources. server.middleware runs before per-route auth checks.
Kết quả
Middleware executes before/after route handlers. Returning a Response short-circuits the request. The mapUserToResourceId callback automatically filters thread listings to the authenticated user, validates thread access with 403 for unauthorized access, and forces thread creation to use the authenticated user’s ID.
Điều kiện áp dụng
Requires @mastra/core package. Works across all server adapters (Hono, Express, Next.js).
Nội dung gốc (Original)
Middleware
Mastra servers can execute custom middleware functions before or after an API route handler is invoked. This is useful for things like authentication, logging, injecting request-specific context or adding CORS headers.
A middleware receives the Hono Context (c) and a next function. If it returns a Response the request is short-circuited. Calling next() continues processing the next middleware or route handler.
import { Mastra } from '@mastra/core'
export const mastra = new Mastra({
server: {
middleware: [
{
handler: async (c, next) => {
// Example: Add authentication check
const authHeader = c.req.header('Authorization')
if (!authHeader) {
return new Response('Unauthorized', { status: 401 })
}
await next()
},
path: '/api/*',
},
// Add a global request logger
async (c, next) => {
console.log(`${c.req.method} ${c.req.url}`)
await next()
},
],
},
})To attach middleware to a single route pass the middleware option to registerApiRoute:
registerApiRoute('/my-custom-route', {
method: 'GET',
middleware: [
async (c, next) => {
console.log(`${c.req.method} ${c.req.url}`)
await next()
},
],
handler: async c => {
const mastra = c.get('mastra')
return c.json({ message: 'Hello, world!' })
},
})Common examples
Using RequestContext
You can populate RequestContext dynamically in server middleware by extracting information from the request. In this example, the temperature-unit is set based on the Cloudflare CF-IPCountry header to ensure responses match the user’s locale.
import { Mastra } from '@mastra/core'
import { RequestContext } from '@mastra/core/request-context'
import { testWeatherAgent } from './agents/test-weather-agent'
export const mastra = new Mastra({
agents: { testWeatherAgent },
server: {
middleware: [
async (context, next) => {
const country = context.req.header('CF-IPCountry')
const requestContext = context.get('requestContext')
requestContext.set('temperature-unit', country === 'US' ? 'fahrenheit' : 'celsius')
await next()
},
],
},
})Authentication
{
handler: async (c, next) => {
const authHeader = c.req.header('Authorization');
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return new Response('Unauthorized', { status: 401 });
}
// Validate token here
await next();
},
path: '/api/*',
}Authorization (User Isolation)
Authentication verifies who the user is. Authorization controls what they can access. Without resource ID scoping, an authenticated user could access other users’ threads by guessing IDs or manipulating the resourceId parameter.
The simplest way to scope memory and threads to the authenticated user is the mapUserToResourceId callback in the auth config:
import { Mastra } from '@mastra/core'
export const mastra = new Mastra({
server: {
auth: {
authenticateToken: async token => {
return verifyToken(token) // { id: 'user-123', orgId: 'org-456', ... }
},
mapUserToResourceId: user => user.id,
},
},
})After successful authentication, mapUserToResourceId is called with the authenticated user object. The returned value is set as MASTRA_RESOURCE_ID_KEY on the request context, which works across all server adapters (Hono, Express, Next.js, etc.).
The resource ID doesn’t have to be user.id. Common patterns:
// Org-scoped
mapUserToResourceId: user => `${user.orgId}:${user.id}`
// From a JWT claim
mapUserToResourceId: user => user.tenantId
// Composite key
mapUserToResourceId: user => `${user.workspaceId}:${user.projectId}:${user.id}`With a resource ID set, the server automatically:
- Filters thread listing to only return threads owned by the user
- Validates thread access and returns 403 if accessing another user’s thread
- Forces thread creation to use the authenticated user’s ID
- Validates message operations including deletion, ensuring messages belong to owned threads
Even if a client passes ?resourceId=other-user-id, the auth-set value takes precedence. Attempts to access threads or messages owned by other users will return a 403 error.
Advanced: Setting resource ID in middleware
For more complex scenarios (e.g., looking up the resource ID from a database), you can set MASTRA_RESOURCE_ID_KEY directly in middleware:
import { Mastra } from '@mastra/core'
import { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context'
import { getAuthenticatedUser } from '@mastra/server/auth'
export const mastra = new Mastra({
server: {
auth: {
authenticateToken: async token => verifyToken(token),
},
middleware: [
{
path: '/api/*',
handler: async (c, next) => {
const token = c.req.header('Authorization')
if (!token) {
return c.json({ error: 'Unauthorized' }, 401)
}
const user = await getAuthenticatedUser<{ id: string }>({
mastra: c.get('mastra'),
token,
request: c.req.raw,
})
const requestContext = c.get('requestContext')
if (!user) {
return c.json({ error: 'Unauthorized' }, 401)
}
requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id)
return next()
},
},
],
},
})server.middleware runs before Mastra’s per-route auth checks. When middleware needs the authenticated user, call getAuthenticatedUser() to resolve it from the configured auth provider without changing the default route auth flow.
Using MASTRA_THREAD_ID_KEY
You can also set MASTRA_THREAD_ID_KEY to override the client-provided thread ID:
import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from '@mastra/core/request-context'
// Force operations to use a specific thread
requestContext.set(MASTRA_THREAD_ID_KEY, validatedThreadId)This is useful when you want to restrict operations to a specific thread that you’ve validated through other means.
CORS support
{
handler: async (c, next) => {
c.header('Access-Control-Allow-Origin', '*');
c.header(
'Access-Control-Allow-Methods',
'GET, POST, PUT, DELETE, OPTIONS',
);
c.header(
'Access-Control-Allow-Headers',
'Content-Type, Authorization',
);
if (c.req.method === 'OPTIONS') {
return new Response(null, { status: 204 });
}
await next();
},
}Request logging
{
handler: async (c, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
console.log(`${c.req.method} ${c.req.url} - ${duration}ms`);
},
}Related
Liên kết
- Nền tảng: Dev Framework · Mastra
- Nguồn: https://mastra.ai/docs/server/middleware
Xem thêm: