Composite Auth
CompositeAuth 類別可讓你將多個驗證 Provider 合併為單一驗證處理常式。它會依序嘗試每個 Provider,直到其中一個成功為止。
使用情境「使用情境」的直接連結
- 同時支援 API 金鑰與 OAuth 權杖
- 在驗證 Provider 之間移轉,且不中斷現有用戶端
- 允許多個身分 Provider(例如網頁使用 Clerk、整合使用 API 金鑰)
- 逐步推出新的驗證方法
安裝「安裝」的直接連結
CompositeAuth 已包含在 @mastra/core 中,不需要其他套件。
import { CompositeAuth } from '@mastra/core/server'
使用範例「使用範例」的直接連結
結合 SimpleAuth(用於 API 金鑰)與 Clerk(用於使用者工作階段):
src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { CompositeAuth, SimpleAuth } from '@mastra/core/server'
import { MastraAuthClerk } from '@mastra/auth-clerk'
// API key users
type ApiKeyUser = {
id: string
name: string
type: 'api-key'
}
const apiKeyAuth = new SimpleAuth<ApiKeyUser>({
tokens: {
'sk-integration-key-123': {
id: 'integration-1',
name: 'CI/CD Pipeline',
type: 'api-key',
},
},
})
// Clerk users (from web app)
const clerkAuth = new MastraAuthClerk({
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
secretKey: process.env.CLERK_SECRET_KEY,
jwksUri: process.env.CLERK_JWKS_URI,
})
export const mastra = new Mastra({
server: {
auth: new CompositeAuth([apiKeyAuth, clerkAuth]),
},
})
運作方式「運作方式」的直接連結
收到請求時,CompositeAuth 會:
- 從
Authorization標頭擷取權杖 - 依序嘗試每個 Provider 的
authenticateToken()方法 - 傳回第一個成功 Provider 的使用者
- 如果所有 Provider 都失敗,則傳回
null(401 Unauthorized)
進行授權時,它會呼叫每個 Provider 的 authorizeUser() 方法,直到其中一個傳回 true。
// Pseudocode of CompositeAuth behavior
async authenticateToken(token, request) {
for (const provider of this.providers) {
const user = await provider.authenticateToken(token, request);
if (user) return user; // First match wins
}
return null; // All providers failed
}
Provider 順序「Provider 順序」的直接連結
由於 Provider 的順序會影響效能,請將最常用的驗證方法放在最前面:
// If most requests use Clerk, put it first
new CompositeAuth([
clerkAuth, // Checked first (most common)
apiKeyAuth, // Checked second (less common)
])
// If most requests use API keys, put it first
new CompositeAuth([
apiKeyAuth, // Checked first (most common)
clerkAuth, // Checked second (less common)
])
多個 OAuth Provider「多個 OAuth Provider」的直接連結
支援來自不同身分 Provider 的使用者:
import { CompositeAuth } from '@mastra/core/server'
import { MastraAuthClerk } from '@mastra/auth-clerk'
import { MastraAuthAuth0 } from '@mastra/auth-auth0'
const clerkAuth = new MastraAuthClerk({
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
secretKey: process.env.CLERK_SECRET_KEY,
jwksUri: process.env.CLERK_JWKS_URI,
})
const auth0Auth = new MastraAuthAuth0({
domain: process.env.AUTH0_DOMAIN,
audience: process.env.AUTH0_AUDIENCE,
})
export const mastra = new Mastra({
server: {
auth: new CompositeAuth([clerkAuth, auth0Auth]),
},
})
移轉範例「移轉範例」的直接連結
從 JWT 移轉至 Clerk,同時維持向下相容性:
import { CompositeAuth } from '@mastra/core/server'
import { MastraJwtAuth } from '@mastra/auth'
import { MastraAuthClerk } from '@mastra/auth-clerk'
// Legacy JWT auth (existing clients)
const legacyAuth = new MastraJwtAuth({
secret: process.env.JWT_SECRET,
})
// New Clerk auth (new clients)
const clerkAuth = new MastraAuthClerk({
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
secretKey: process.env.CLERK_SECRET_KEY,
jwksUri: process.env.CLERK_JWKS_URI,
})
// Support both during migration
export const mastra = new Mastra({
server: {
auth: new CompositeAuth([
clerkAuth, // New auth method (preferred)
legacyAuth, // Legacy support
]),
},
})
搭配自訂 Provider「搭配自訂 Provider」的直接連結
結合內建 Provider 與自訂實作:
import { CompositeAuth, SimpleAuth } from '@mastra/core/server'
import { MyCustomAuth } from './my-custom-auth'
const apiKeyAuth = new SimpleAuth({
tokens: {
'sk-key-123': { id: 'user-1', name: 'API User' },
},
})
const customAuth = new MyCustomAuth({
apiUrl: process.env.CUSTOM_AUTH_URL,
})
export const mastra = new Mastra({
server: {
auth: new CompositeAuth([apiKeyAuth, customAuth]),
},
})
錯誤處理「錯誤處理」的直接連結
CompositeAuth 會靜默攔截個別 Provider 的錯誤,並繼續嘗試下一個。這可避免單一 Provider 發生錯誤時阻擋驗證:
// If clerkAuth throws an error, apiKeyAuth still gets tried
new CompositeAuth([clerkAuth, apiKeyAuth])
若要偵錯驗證問題,請在自訂 Provider 中加入記錄,或檢查各個 Provider 的設定。
限制「限制」的直接連結
- 所有 Provider 共用來自
Authorization標頭的相同權杖 - 各 Provider 的使用者型別可能不同(如有需要,請使用可辨識聯集)
- 沒有內建方式可識別是哪個 Provider 驗證了請求
處理不同的使用者型別「處理不同的使用者型別」的直接連結
當 Provider 傳回不同的使用者型別時,請使用可辨識聯集:
type ApiKeyUser = {
type: 'api-key'
id: string
name: string
}
type ClerkUser = {
type: 'clerk'
sub: string
email: string
}
type User = ApiKeyUser | ClerkUser
// In your application code
function handleUser(user: User) {
if (user.type === 'api-key') {
console.log('API key user:', user.name)
} else {
console.log('Clerk user:', user.email)
}
}