細粒度授權(FGA)
細粒度授權是 Mastra Enterprise Edition 的一部分。正式環境部署需要有效的 EE 授權。如需更多資訊,請聯絡業務團隊。
細粒度授權(FGA)會為 Mastra 應用程式加入資源層級的權限檢查。RBAC 回答的是「這個角色能否執行此動作?」,FGA 回答的則是**「這位使用者能否對這個特定資源執行此動作?」**
適合使用 FGA 的情況「適合使用 FGA 的情況」的直接連結
FGA 專為權限取決於情境的多租戶 B2B 產品而設計:
- 使用者可能是團隊 A 的管理員,但只是團隊 B 的成員
- Thread 存取權應限於使用者自己的組織
- Workflow 執行應限於特定團隊或專案
- Tool 存取權取決於使用者與資源的關係
設定「設定」的直接連結
在 Mastra 伺服器設定中,將 FGA 與驗證及 RBAC 一併設定:
import { Mastra } from '@mastra/core/mastra';
import { MastraFGAPermissions } from '@mastra/core/auth/ee';
import { MastraAuthWorkos, MastraFGAWorkos } from '@mastra/auth-workos';
const mastra = new Mastra({
server: {
auth: new MastraAuthWorkos({
/* ... */
fetchMemberships: true,
mapUserToResourceId: user => user.teamId,
}),
fga: new MastraFGAWorkos({
resourceMapping: {
agent: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId },
workflow: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId },
thread: { fgaResourceType: 'workspace-thread', deriveId: ({ resourceId }) => resourceId },
},
permissionMapping: {
[MastraFGAPermissions.AGENTS_EXECUTE]: 'manage-workflows',
[MastraFGAPermissions.WORKFLOWS_EXECUTE]: 'manage-workflows',
[MastraFGAPermissions.MEMORY_READ]: 'read',
[MastraFGAPermissions.MEMORY_WRITE]: 'update',
},
}),
storedResources: {
scope: true,
},
},
});
使用 MastraFGAWorkos 時,請在 MastraAuthWorkos 上設定 fetchMemberships: true。WorkOS FGA 檢查需要使用者的 organization membership,才能解析授權所需的正確 membership ID。
進行 memory 授權時,請使用 thread 作為資源對應 key。MastraFGAWorkos 仍接受舊版別名 memory,但新設定應優先使用 thread。
設定 server.fga 後,Mastra 會對受保護動作強制執行 FGA。若受保護動作沒有已驗證的使用者,Mastra 會拒絕該動作。若未設定 server.fga,則會略過這些 FGA 檢查,Mastra 會維持先前的行為。
資源對應「資源對應」的直接連結
resourceMapping 會告訴 Mastra 如何從 request context 解析 FGA 資源類型與 ID。Key 是 Mastra 資源類型,value 則定義 FGA 資源類型及 ID 的衍生方式:
resourceMapping: {
// When checking "can user execute agent X?", resolve the FGA resource
// as the user's team (type: 'team', id: user.teamId)
agent: {
fgaResourceType: 'team',
deriveId: (ctx) => ctx.user.teamId,
},
}
deriveId() 會接收:
user:已驗證的使用者resourceId:可用時,所屬 Mastra 資源的 ID(例如 thread 的resourceId)requestContext:用於進階 tenant 解析的目前 request contextmetadata:嘗試執行之動作的 Provider 特定 metadata
從 deriveId() 傳回 undefined,即可改用原始 Mastra 資源 ID。
進行 thread 與 memory 檢查時,Mastra 仍會將原始 threadId 作為受檢查資源傳入,但也會將 thread 所屬的 resourceId 轉送至 deriveId()。因此,你可以將 thread 權限對應至 userId-teamId-orgId 等複合 tenant ID。
權限對應「權限對應」的直接連結
permissionMapping 會將 Mastra 的內部權限字串轉換為 FGA Provider 的權限 slug:
import { MastraFGAPermissions } from '@mastra/core/auth/ee';
permissionMapping: {
[MastraFGAPermissions.AGENTS_EXECUTE]: 'manage-workflows', // Mastra permission -> WorkOS permission slug
[MastraFGAPermissions.MEMORY_READ]: 'read',
}
若權限沒有對應項目,系統會直接傳入原始字串。
使用 validatePermissions(),在啟動時驗證 Mastra 可能發出的完整權限集合。當 Provider 要求每項 Mastra 權限都必須具有明確的 Provider 權限 slug 時,請使用此方法。
儲存資源的 scope「儲存資源的 scope」的直接連結
FGA 會授權資源存取,但不會自動篩選位於共用儲存空間的已儲存記錄。在多租戶應用程式中使用內建的已儲存資源 API 時,請啟用已儲存資源的 scope。
const mastra = new Mastra({
server: {
auth: new MastraAuthWorkos({
/* ... */
mapUserToResourceId: user => user.teamId,
}),
storedResources: {
scope: true,
},
},
});
設定 scope: true 後,Mastra 會從 request context 讀取 MASTRA_RESOURCE_ID_KEY。mapUserToResourceId() 會在驗證後設定此值。已儲存資源 handler 會將 scope 保存於記錄 metadata,並依該 scope 篩選列出、讀取、更新、發布與刪除操作。
當 scope 需要自訂請求邏輯時,請使用物件:
storedResources: {
scope: {
metadataKey: 'teamId',
resolve: ({ user }) => user.teamId,
requireScope: true,
},
},
若 requireScope 為 true 或省略,當無法解析 scope 時,具 scope 的已儲存資源 route 會失敗。
Route policy 涵蓋範圍「Route policy 涵蓋範圍」的直接連結
Mastra 為內建資源 route 提供 route 層級的 FGA metadata,涵蓋 Agent、Workflow、Tool、MCP Tool、memory thread、response、conversation 與已儲存資源。已儲存資源 route 涵蓋 /stored/agents、/stored/mcp-clients、/stored/prompt-blocks、/stored/scorers、/stored/skills 與 /stored/workspaces。當 route 具有 route 層級的 fga metadata、Mastra 可為該 route 衍生內建 metadata,或 Provider 透過 resolveRouteFGA() 提供 metadata 時,系統就會檢查該 route。
若要拒絕無法解析 FGA metadata 的受保護 route,請在 FGA Provider 上設定 route policy 涵蓋範圍:
const fga = new MastraFGAWorkos({
resourceMapping: {
project: { fgaResourceType: 'project' },
},
permissionMapping: {
'projects:read': 'read',
},
requireForProtectedRoutes: true,
auditProtectedRoutes: 'warn',
validatePermissions: async permissions => {
// Throw if a Mastra permission is missing from permissionMapping.
},
});
將 auditProtectedRoutes: 'error' 設為在受保護 route 缺少內建 FGA metadata 時,讓啟動失敗。若啟用 requireForProtectedRoutes,Mastra 預設會將此稽核記錄為警告。
針對自訂 route,請優先使用 route 層級的 fga metadata。這能讓授權 policy 與 route 放在一起:
import { createRoute } from '@mastra/server/server-adapter';
export const getProjectRoute = createRoute({
method: 'GET',
path: '/projects/:projectId',
responseType: 'json',
requiresAuth: true,
fga: {
resourceType: 'project',
resourceIdParam: 'projectId',
permission: 'projects:read',
},
handler: async () => {
return { project: null };
},
});
只有在必須集中依 route、params 或 request context 衍生 route metadata 時,才使用 resolveRouteFGA()。Route map 比字串前綴檢查更容易擴充:
import type { FGARouteConfig, FGARouteResolver } from '@mastra/core/auth/ee';
const routeFGA = {
'GET /billing/:accountId': {
resourceType: 'account',
resourceIdParam: 'accountId',
permission: 'billing:read',
},
} satisfies Record<string, FGARouteConfig>;
const resolveRouteFGA: FGARouteResolver = ({ route }) => routeFGA[`${route.method} ${route.path}`];
const fga = new MastraFGAWorkos({
/* ... */
resolveRouteFGA,
});
強制執行點「強制執行點」的直接連結
設定 FGA Provider 後,Mastra 會在下列生命週期節點自動檢查授權:
| 生命週期節點 | 檢查的權限 | 資源類型 | 資源 ID |
|---|---|---|---|
Agent 執行(generate、stream) | agents:execute | agent | agentId |
內建 Workflow HTTP 執行 route 與 Workflow.execute() | workflows:execute | workflow | workflowId |
| 獨立 Tool 執行 | tools:execute | tool | toolName |
| Agent Tool 執行 | tools:execute | tool | ${agentId}:${toolName} |
| MCP Tool 執行 | tools:execute | 預設為 tool,或伺服器層級的 fga.resourceMapping 覆寫值 | 預設為 JSON.stringify([serverName, toolName]),或伺服器層級衍生的 ID |
| Thread 與 memory 存取 | memory:read、memory:write、memory:delete | thread | threadId |
| 已儲存資源 route | Route 動作的已儲存資源權限 | 已儲存資源類型 | Route 記錄 ID,或 collection route 的已儲存資源 scope |
| HTTP 資源 route | 依 route 設定 | 依 route 設定 | 依 route 設定 |
對於受 OAuth 保護的 MCP 伺服器,HTTP MCP transport 會將已驗證資料以 extra.authInfo 傳入。若在已啟用 FGA 的 Mastra 執行個體上註冊 MCPServer,請設定 mapAuthInfoToUser,讓 Mastra 能在檢查 tools/list 與 tools/call 前設定 requestContext.get('user')。當 MCP Tool 檢查需要與內部 Agent 及 Workflow Tool 檢查不同的資源或權限對應時,請使用伺服器層級的 fga 選項。請參閱 MCPServer 驗證 context。
在此版本中,直接呼叫 SDK 的 createRun().start()、resume() 或 restart() 不會由核心 FGA 個別檢查。請從受保護 route 呼叫這些方法,或在應用程式程式碼中加以防護。直接叫用受保護 entry point 時,請傳入包含已驗證使用者的 requestContext。
核心 Agent、內部 Workflow、Tool 與 memory 檢查也會將 requestContext 和動作 metadata 傳給 FGA Provider。Route 檢查會傳入 requestContext。Thread 檢查會在可用時傳入所屬的 resourceId。
自訂 FGA Provider「自訂 FGA Provider」的直接連結
實作 IFGAProvider 以使用任何 FGA backend:
import { FGADeniedError } from '@mastra/core/auth/ee'
import type { FGACheckParams, IFGAProvider, MastraFGAPermissionInput } from '@mastra/core/auth/ee'
class MyFGAProvider implements IFGAProvider {
async check(user: any, params: FGACheckParams): Promise<boolean> {
// Your authorization logic
return true
}
async require(user: any, params: FGACheckParams): Promise<void> {
const allowed = await this.check(user, params)
if (!allowed) {
throw new FGADeniedError(user, params.resource, params.permission)
}
}
async filterAccessible<T extends { id: string }>(
user: any,
resources: T[],
resourceType: string,
permission: MastraFGAPermissionInput,
): Promise<T[]> {
// Filter resources the user can access
return resources
}
}
如需所有方法、參數與 ActorSignal 類型的說明,請參閱 IFGAProvider 參考文件。
系統 actor「系統 actor」的直接連結
自主與排程的 Agent 會在沒有終端使用者的情況下執行。請使用 actor signal 標記這些呼叫,讓 FGA 能將其與使用者請求區分:
true或{ actorKind: 'system' }代表匿名系統 actor。- 物件形式也可以包含
agentId、permissions與scope,以識別並限制執行動作的 Agent。
受信任 actor 預設會在 tenant scope 檢查後略過以使用者為中心的 require() 檢查。若要強制每個 Agent 遵循最小權限原則,請在 Provider 上實作選用的 requireActor 方法。此方法會接收 actor 與 require 所接收的相同 FGACheckParams,並擲回 FGADeniedError 以拒絕操作。Provider 未實作 requireActor 時,系統會保留受信任 actor 的略過行為,因此加入此方法可向後相容。
import { FGADeniedError } from '@mastra/core/auth/ee'
import type { ActorSignal, FGACheckParams, IFGAProvider } from '@mastra/core/auth/ee'
class MyFGAProvider implements IFGAProvider {
// ...check, require, filterAccessible...
async requireActor(actor: ActorSignal, params: FGACheckParams): Promise<void> {
const agentId = actor === true ? undefined : actor.agentId
// Resolve the agent's real grants from a trusted source keyed by agentId.
const granted = await this.grantsForAgent(agentId)
const required = Array.isArray(params.permission) ? params.permission : [params.permission]
if (!required.some(permission => granted.includes(permission))) {
throw new FGADeniedError(null, params.resource, params.permission)
}
}
}
信任需求「信任需求」的直接連結
Actor signal 是受信任的輸入,因此請在伺服器端建立:
- 將
actor視為每次呼叫各自的 signal。Durable Workflow 會在執行開始時轉送該值,但不會在繼續執行時還原初始 actor。每次受信任的繼續執行都應明確傳入該值,或透過 AgentdefaultOptions解析新的 actor。若沒有目前 actor,則會套用使用者授權,而缺少使用者時會以拒絕方式安全失敗。 - Mastra 會從內建 Agent HTTP route 所處理的執行選項中移除
actor。請在伺服器端程式碼中設定,例如排程工作或 Workflow,切勿使用用戶端輸入。 - 在伺服器端建立 tenant scope。內建 Agent HTTP route 會忽略用戶端在 request context 中提供的
organizationId,且受信任 actor 路徑要求必須設定organizationId。 - Durable resume 會保留既有的 request context 復原與合併行為。這不會讓保存的 actor 在後續 Workflow 區段中成為受信任的 actor。
- Tenant scope 檢查會確認受信任的
organizationId存在,但不會驗證actor.agentId是否屬於該組織。當此關係很重要時,請在requireActor中使用權威的 Provider 資料進行驗證。 - 將
actor.permissions視為未驗證的 claim。請從受信任來源解析權威 grant。強制執行最小權限的 Provider 會從受信任來源解析 Agent 的權威權限,例如以agentId為 key 的 manifest 或 FGA backend,而不是信任 inline value。 - Provider 一旦實作
requireActor,該方法發生錯誤時便會停止執行。Mastra 不會退回僅限組織的授權。