メインコンテンツへ移動

Composite Auth

CompositeAuth クラスを使用すると、複数の認証 Provider を1つの認証ハンドラーにまとめられます。成功するまで、各 Provider を順番に試します。

ユースケース
ユースケースへの直接リンク

  • API キーと OAuth トークンの両方をサポートする
  • 既存のクライアントを停止させずに認証 Provider を移行する
  • 複数のアイデンティティ Provider を利用する(Web には 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 は次の処理を行います。

  1. Authorization ヘッダーからトークンを抽出する
  2. 各 Provider の authenticateToken() メソッドを順番に試す
  3. 最初に成功した Provider からユーザーを返す
  4. すべての Provider が失敗した場合は null(401 Unauthorized)を返す

認可では、いずれかが true を返すまで、各 Provider の authorizeUser() メソッドを呼び出します。

// 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 に進みます。これにより、1つの Provider の障害によって認証全体が妨げられることを防ぎます。

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

認証の問題をデバッグするには、カスタム Provider にログ出力を追加するか、個々の Provider の設定を確認してください。

制限事項
制限事項への直接リンク

  • すべての Provider が Authorization ヘッダーの同じトークンを共有する
  • Provider ごとにユーザー型が異なる場合がある(必要に応じて判別可能な Union 型を使用する)
  • どの Provider がリクエストを認証したかを識別する組み込みの方法がない

異なるユーザー型の処理
異なるユーザー型の処理への直接リンク

Provider が異なるユーザー型を返す場合は、判別可能な 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)
}
}