跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

Composite Auth

CompositeAuth 类允许你将多个认证提供方组合成单个认证处理器。它会按顺序尝试每个提供方,直到有一个成功。

使用场景
使用场景的直接链接

  • 同时支持 API Key 和 OAuth Token
  • 在不破坏现有客户端的情况下迁移认证提供方
  • 支持多个身份提供方(例如 Web 应用使用 Clerk,集成使用 API Key)
  • 逐步推出新的认证方式

安装
安装的直接链接

CompositeAuth 内置于 @mastra/core,无需额外安装包。

import { CompositeAuth } from '@mastra/core/server'

使用示例
使用示例的直接链接

组合 SimpleAuth(用于 API Key)与 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 会:

  1. 从 Authorization 请求头中提取 Token
  2. 按顺序调用每个提供方的 authenticateToken() 方法
  3. 返回第一个成功的提供方所返回的用户
  4. 如果所有提供方都失败,则返回 null(401 Unauthorized)

对于授权,它会依次调用每个提供方的 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
}

提供方顺序
提供方顺序的直接链接

将最常见的认证方式放在最前面,因为提供方顺序会影响性能:

// 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 提供方
多个 OAuth 提供方的直接链接

支持来自不同身份提供方的用户:

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
]),
},
})

自定义提供方
自定义提供方的直接链接

将内置提供方与自定义实现组合:

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 会静默捕获各个提供方的错误,并继续尝试下一个提供方。这可防止单个提供方故障阻塞认证:

// If clerkAuth throws an error, apiKeyAuth still gets tried
new CompositeAuth([clerkAuth, apiKeyAuth])

要调试认证问题,可为自定义提供方添加日志,或检查各个提供方的配置。

限制
限制的直接链接

  • 所有提供方共享同一个 Token,该 Token 来自 Authorization 请求头;当该请求头缺失时,来自 apiKey 查询参数
  • 不同提供方返回的用户类型可能不同(如有需要,可使用可辨识联合类型)
  • 没有内置方式识别某个请求是由哪个提供方完成认证的

处理不同的用户类型
处理不同的用户类型的直接链接

当提供方返回不同的用户类型时,使用可辨识联合类型:

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)
}
}
On this page