Composite Auth - Kết Hợp Nhiều Nhà Cung Cấp Xác Thực Trong Mastra
Trust: ★★★☆☆ (0.90) · 0 validations · factual
Published: 2026-05-09 · Source: crawler_authoritative
Tình huống
Tài liệu kỹ thuật về class CompositeAuth trong framework Mastra, dùng để kết hợp nhiều authentication providers thành một auth handler duy nhất.
Insight
CompositeAuth là class trong @mastra/core cho phép kết hợp nhiều nhà cung cấp xác thực (authentication providers) thành một handler duy nhất. Class này thử lần lượt từng provider theo thứ tự cho đến khi có provider thành công. Các use cases chính bao gồm: hỗ trợ cả API keys và OAuth tokens, migrate giữa các auth providers mà không làm break clients hiện tại, cho phép nhiều identity providers (ví dụ Clerk cho web, API keys cho integrations), và gradual rollout các phương thức xác thực mới. Cách hoạt động: CompositeAuth extract token từ Authorization header, thử lần lượt mỗi provider’s authenticateToken() method, trả về user từ provider đầu tiên thành công, hoặc trả về null (401 Unauthorized) nếu tất cả đều thất bại. Thứ tự providers rất quan trọng vì provider đầu tiên được check trước - nên đặt phương thức phổ biến nhất lên đầu để tối ưu hiệu suất. Error handling: CompositeAuth silently catches errors từ các individual providers và chuyển sang provider tiếp theo, ngăn một provider thất bại không block toàn bộ authentication. Limitations: tất cả providers chia sẻ cùng một token từ Authorization header, user types có thể khác nhau giữa các providers (cần dùng discriminated unions), và không có cách built-in để xác định provider nào đã authenticate request.
Hành động
Import CompositeAuth từ ‘@mastra/core/server’. Khởi tạo từng provider riêng lẻ (SimpleAuth cho API keys, MastraAuthClerk cho Clerk, MastraAuthAuth0 cho Auth0, MastraJwtAuth cho JWT). Truyền array các providers vào CompositeAuth([provider1, provider2, …]). Đặt provider phổ biến nhất ở đầu array để tối ưu performance. Khi cần handle các user types khác nhau, sử dụng discriminated union type (ví dụ: type ApiKeyUser = { type: ‘api-key’, id: string, name: string } | type ClerkUser = { type: ‘clerk’, sub: string, email: string }). Để debug, thêm logging vào custom providers hoặc kiểm tra từng provider configuration riêng lẻ.
Điều kiện áp dụng
Tất cả providers phải chia sẻ cùng một token từ Authorization header. User types có thể khác nhau giữa các providers. Không có cách built-in để xác định provider nào đã authenticate request. CompositeAuth chỉ hỗ trợ các providers có interface authenticateToken() và authorizeUser() methods.
Nội dung gốc (Original)
Composite Auth
The CompositeAuth class allows you to combine multiple authentication providers into a single auth handler. It tries each provider in order until one succeeds.
Use cases
- Support both API keys and OAuth tokens
- Migrate between auth providers without breaking existing clients
- Allow multiple identity providers (e.g., Clerk for web, API keys for integrations)
- Gradual rollout of new authentication methods
Installation
CompositeAuth is included in @mastra/core, no additional packages required.
import { CompositeAuth } from '@mastra/core/server'Usage example
Combine SimpleAuth (for API keys) with Clerk (for user sessions):
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]),
},
})How it works
When a request comes in, CompositeAuth:
- Extracts the token from the
Authorizationheader - Tries each provider’s
authenticateToken()method in order - Returns the user from the first provider that succeeds
- Returns
null(401 Unauthorized) if all providers fail
For authorization, it calls each provider’s authorizeUser() method until one returns 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 order
The order of providers matters. Place the most common authentication method first for better performance:
// 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)
])Multiple OAuth providers
Support users from different identity providers:
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]),
},
})Migration example
Migrate from JWT to Clerk while maintaining backwards compatibility:
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
]),
},
})With custom providers
Combine built-in providers with custom implementations:
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]),
},
})Error handling
CompositeAuth silently catches errors from individual providers and moves to the next one. This prevents one failing provider from blocking authentication:
// If clerkAuth throws an error, apiKeyAuth still gets tried
new CompositeAuth([clerkAuth, apiKeyAuth])To debug authentication issues, add logging to your custom providers or check individual provider configurations.
Limitations
- All providers share the same token from the
Authorizationheader - User types may differ between providers (use discriminated unions if needed)
- No built-in way to identify which provider authenticated a request
Handling Different User Types
When providers return different user types, use a discriminated union:
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)
}
}Liên kết
- Nền tảng: Chung
- Nguồn: https://mastra.ai/docs/server/auth/composite-auth
Xem thêm: