맞춤 인증 Provider
사용자 정의 인증 공급자를 사용하면 기본 제공 공급자가 처리하지 않는 ID 시스템에 대한 인증을 구현할 수 있습니다. 확장MastraAuthProvider모든 인증 시스템과 통합할 수 있는 기본 클래스입니다.
개요개요에 대한 직접 링크
인증 공급자는 들어오는 요청에 대한 인증 및 권한 부여를 처리합니다.
- 토큰 검증 및 사용자 추출
- 사용자 인증 로직
- 경로 기반 액세스 제어(공개/보호 경로)
다음을 지원하는 사용자 정의 인증 공급자를 만듭니다.
- 자체 호스팅 ID 시스템
- 사용자 정의 토큰 형식 또는 확인 논리
- 특수 권한 부여 규칙
- 엔터프라이즈 SSO 통합
사용자 정의 인증 공급자 만들기사용자 정의 인증 공급자 만들기에 대한 직접 링크
MastraAuthProvider 클래스를 확장하고 필수 메서드를 구현하세요.
import { MastraAuthProvider } from '@mastra/core/server'
import type { MastraAuthProviderOptions } from '@mastra/core/server'
import type { HonoRequest } from 'hono'
// Define your user type
type MyUser = {
id: string
email: string
roles: string[]
}
// Define options for your provider
interface MyAuthOptions extends MastraAuthProviderOptions<MyUser> {
apiUrl?: string
apiKey?: string
}
export class MyAuthProvider extends MastraAuthProvider<MyUser> {
protected apiUrl: string
protected apiKey: string
constructor(options?: MyAuthOptions) {
// Call super with a name for logging/debugging
super({ name: options?.name ?? 'my-auth' })
const apiUrl = options?.apiUrl ?? process.env.MY_AUTH_API_URL
const apiKey = options?.apiKey ?? process.env.MY_AUTH_API_KEY
if (!apiUrl || !apiKey) {
throw new Error(
'Auth API URL and API key are required. Provide them in options or set MY_AUTH_API_URL and MY_AUTH_API_KEY environment variables.',
)
}
this.apiUrl = apiUrl
this.apiKey = apiKey
// Register any custom options (authorizeUser override, public/protected paths)
this.registerOptions(options)
}
/**
* Verify the token and return the user
* Return null if authentication fails
*/
async authenticateToken(token: string, request: HonoRequest): Promise<MyUser | null> {
try {
const response = await fetch(`${this.apiUrl}/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
},
body: JSON.stringify({ token }),
})
if (!response.ok) {
return null
}
const user = await response.json()
return user
} catch (error) {
console.error('Token verification failed:', error)
return null
}
}
/**
* Check if the authenticated user is authorized
* Return true to allow access, false to deny
*/
async authorizeUser(user: MyUser, request: HonoRequest): Promise<boolean> {
// Basic authorization: user must exist and have an ID
return !!user?.id
}
}
필수 방법필수 방법에 대한 직접 링크
authenticateToken()authenticatetoken에 대한 직접 링크
수신 토큰을 검증하고 유효하면 사용자 객체를 반환합니다. 인증에 실패하면 null을 반환합니다.
async authenticateToken(token: string, request: HonoRequest): Promise<TUser | null>
| 매개변수 | 유형 | 설명 |
|---|---|---|
token | string | Authorization 헤더에서 추출한 Bearer 토큰 |
request | HonoRequest | 수신 요청 객체(헤더, 쿠키 등에 접근 가능) |
반환값: 인증에 성공하면 사용자 객체를, 실패하면 null을 반환합니다. | ||
토큰은 Authorization: Bearer <token> 헤더에서 자동으로 추출됩니다. 다른 헤더나 쿠키에 접근해야 한다면 request 매개변수를 사용하세요. |
authorizeUser()authorizeuser에 대한 직접 링크
인증된 사용자가 리소스에 액세스할 수 있는지 확인합니다.
async authorizeUser(user: TUser, request: HonoRequest): Promise<boolean> | boolean
| 매개변수 | 유형 | 설명 |
|---|---|---|
user | TUser | authenticateToken이 반환한 사용자 객체 |
request | HonoRequest | 수신 요청 객체 |
반환값: 액세스를 허용하려면 true, 거부하려면 false를 반환합니다(403 Forbidden 반환). |
구성 옵션구성 옵션에 대한 직접 링크
그만큼MastraAuthProviderOptions interface supports these options:
| 옵션 | 유형 | 설명 |
|---|---|---|
name | string | 로깅/디버깅에 사용할 Provider 이름 |
authorizeUser | (user, request) => Promise<boolean> | boolean | 사용자 지정 권한 부여 함수 |
protected | (RegExp | string | [string, Methods | Methods[]])[] | 인증이 필요한 경로 |
public | (RegExp | string | [string, Methods | Methods[]])[] | 인증을 우회하는 경로 |
경로 패턴경로 패턴에 대한 직접 링크
패턴 일치를 사용하여 인증이 필요한 경로를 구성합니다.
const auth = new MyAuthProvider({
// Paths that require authentication
protected: [
'/api/*', // Wildcard: all /api routes
'/admin/*', // Wildcard: all /admin routes
/^\/secure\/.*/, // Regex pattern
],
// Paths that bypass authentication
public: [
'/health', // Exact match
'/api/status', // Exact match
['/api/webhook', 'POST'], // Only POST requests to /api/webhook
],
})
인증 공급자 사용인증 공급자 사용에 대한 직접 링크
Mastra 인스턴스에 사용자 정의 인증 공급자를 등록합니다.
import { Mastra } from '@mastra/core'
import { MyAuthProvider } from './my-auth-provider'
export const mastra = new Mastra({
server: {
auth: new MyAuthProvider({
apiUrl: process.env.MY_AUTH_API_URL,
apiKey: process.env.MY_AUTH_API_KEY,
}),
},
})
도우미 유틸리티도우미 유틸리티에 대한 직접 링크
@mastra/auth 패키지는 일반적인 토큰 검증 패턴을 위한 유틸리티를 제공합니다.
JWT 검증JWT 검증에 대한 직접 링크
import { verifyHmac, verifyJwks, decodeToken, getTokenIssuer } from '@mastra/auth'
// Verify HMAC-signed JWT
const payload = await verifyHmac(token, 'your-secret-key')
// Verify with JWKS (for OAuth providers)
const payload = await verifyJwks(token, 'https://provider.com/.well-known/jwks.json')
// Decode without verification (for inspection)
const decoded = await decodeToken(token)
// Get the issuer from a decoded token
const issuer = getTokenIssuer(decoded)
예: JWKS 기반 제공자예: JWKS 기반 제공자에 대한 직접 링크
import { MastraAuthProvider } from '@mastra/core/server'
import type { MastraAuthProviderOptions } from '@mastra/core/server'
import { verifyJwks } from '@mastra/auth'
import type { JwtPayload } from '@mastra/auth'
type MyUser = JwtPayload
interface MyJwksAuthOptions extends MastraAuthProviderOptions<MyUser> {
jwksUri?: string
issuer?: string
}
export class MyJwksAuth extends MastraAuthProvider<MyUser> {
protected jwksUri: string
protected issuer: string
constructor(options?: MyJwksAuthOptions) {
super({ name: options?.name ?? 'my-jwks-auth' })
const jwksUri = options?.jwksUri ?? process.env.MY_JWKS_URI
const issuer = options?.issuer ?? process.env.MY_AUTH_ISSUER
if (!jwksUri) {
throw new Error('JWKS URI is required')
}
this.jwksUri = jwksUri
this.issuer = issuer ?? ''
this.registerOptions(options)
}
async authenticateToken(token: string): Promise<MyUser | null> {
try {
const payload = await verifyJwks(token, this.jwksUri)
// Optionally validate issuer
if (this.issuer && payload.iss !== this.issuer) {
return null
}
return payload
} catch {
return null
}
}
async authorizeUser(user: MyUser): Promise<boolean> {
// Check token hasn't expired
if (user.exp && user.exp * 1000 < Date.now()) {
return false
}
return !!user.sub
}
}
맞춤 인증 논리맞춤 인증 논리에 대한 직접 링크
사용자 정의를 제공하여 기본 인증을 재정의합니다.authorizeUser function:
const auth = new MyAuthProvider({
apiUrl: process.env.MY_AUTH_API_URL,
apiKey: process.env.MY_AUTH_API_KEY,
// Custom authorization: require admin role for all requests
async authorizeUser(user, request) {
return user.roles.includes('admin')
},
})
역할 기반 인증역할 기반 인증에 대한 직접 링크
const auth = new MyAuthProvider({
async authorizeUser(user, request) {
const path = request.url
const method = request.method
// Admin routes require admin role
if (path.startsWith('/admin/')) {
return user.roles.includes('admin')
}
// Write operations require write role
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
return user.roles.includes('write') || user.roles.includes('admin')
}
// Read operations allowed for all authenticated users
return true
},
})
사용자 정의 인증 공급자 테스트사용자 정의 인증 공급자 테스트에 대한 직접 링크
Vitest를 사용한 테스트 구조 예시:
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { MyAuthProvider } from './my-auth-provider'
// Mock fetch for API calls
global.fetch = vi.fn()
describe('MyAuthProvider', () => {
const mockOptions = {
apiUrl: 'https://auth.example.com',
apiKey: 'test-api-key',
}
beforeEach(() => {
vi.clearAllMocks()
})
describe('initialization', () => {
it('should initialize with provided options', () => {
const auth = new MyAuthProvider(mockOptions)
expect(auth).toBeInstanceOf(MyAuthProvider)
})
it('should throw error when required options are missing', () => {
expect(() => new MyAuthProvider({})).toThrow('Auth API URL and API key are required')
})
})
describe('authenticateToken', () => {
it('should return user when token is valid', async () => {
const mockUser = { id: 'user123', email: 'test@example.com', roles: ['read'] }
;(fetch as any).mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockUser),
})
const auth = new MyAuthProvider(mockOptions)
const result = await auth.authenticateToken('valid-token', {} as any)
expect(fetch).toHaveBeenCalledWith(
'https://auth.example.com/verify',
expect.objectContaining({
method: 'POST',
body: JSON.stringify({ token: 'valid-token' }),
}),
)
expect(result).toEqual(mockUser)
})
it('should return null when token is invalid', async () => {
;(fetch as any).mockResolvedValue({ ok: false })
const auth = new MyAuthProvider(mockOptions)
const result = await auth.authenticateToken('invalid-token', {} as any)
expect(result).toBeNull()
})
})
describe('authorizeUser', () => {
it('should return true when user has valid id', async () => {
const auth = new MyAuthProvider(mockOptions)
const result = await auth.authorizeUser(
{ id: 'user123', email: 'test@example.com', roles: [] },
{} as any,
)
expect(result).toBe(true)
})
it('should return false when user has no id', async () => {
const auth = new MyAuthProvider(mockOptions)
const result = await auth.authorizeUser(
{ id: '', email: 'test@example.com', roles: [] },
{} as any,
)
expect(result).toBe(false)
})
})
describe('custom authorization', () => {
it('should use custom authorizeUser when provided', async () => {
const auth = new MyAuthProvider({
...mockOptions,
authorizeUser: user => user.roles.includes('admin'),
})
const adminUser = { id: 'user123', email: 'admin@example.com', roles: ['admin'] }
const regularUser = { id: 'user456', email: 'user@example.com', roles: ['read'] }
expect(await auth.authorizeUser(adminUser, {} as any)).toBe(true)
expect(await auth.authorizeUser(regularUser, {} as any)).toBe(false)
})
})
describe('route configuration', () => {
it('should store public routes configuration', () => {
const publicRoutes = ['/health', '/api/status']
const auth = new MyAuthProvider({
...mockOptions,
public: publicRoutes,
})
expect(auth.public).toEqual(publicRoutes)
})
it('should store protected routes configuration', () => {
const protectedRoutes = ['/api/*', '/admin/*']
const auth = new MyAuthProvider({
...mockOptions,
protected: protectedRoutes,
})
expect(auth.protected).toEqual(protectedRoutes)
})
})
})
오류 처리오류 처리에 대한 직접 링크
일반적인 오류 시나리오에 대한 설명 오류를 제공합니다.
export class MyAuthProvider extends MastraAuthProvider<MyUser> {
constructor(options?: MyAuthOptions) {
super({ name: options?.name ?? 'my-auth' })
const apiUrl = options?.apiUrl ?? process.env.MY_AUTH_API_URL
const apiKey = options?.apiKey ?? process.env.MY_AUTH_API_KEY
if (!apiUrl) {
throw new Error(
'Missing MY_AUTH_API_URL. Set the environment variable or pass apiUrl in options.',
)
}
if (!apiKey) {
throw new Error(
'Missing MY_AUTH_API_KEY. Set the environment variable or pass apiKey in options.',
)
}
this.apiUrl = apiUrl
this.apiKey = apiKey
this.registerOptions(options)
}
async authenticateToken(token: string): Promise<MyUser | null> {
if (!token || typeof token !== 'string') {
return null // Immediate safe fail
}
try {
const response = await fetch(`${this.apiUrl}/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
},
body: JSON.stringify({ token }),
})
if (!response.ok) {
return null
}
return await response.json()
} catch (error) {
// Log error for debugging, but don't expose details to client
console.error('Auth verification error:', error)
return null
}
}
}
내장 공급자내장 공급자에 대한 직접 링크
Mastra에는 다음 인증 공급자가 참조 구현으로 포함되어 있습니다.
- 마스트라JwtAuth: HMAC 비밀을 사용한 간단한 JWT 확인(
@mastra/auth) - MastraAuthClerk: 사무원 인증 (
@mastra/auth-clerk) - MastraAuthAuth0: 인증0 인증(
@mastra/auth-auth0) - MastraAuthSupabase: Superbase 인증(
@mastra/auth-supabase) - MastraAuthFirebase: Firebase 인증(
@mastra/auth-firebase) - MastraAuthWorkOS: WorkOS 인증(
@mastra/auth-workos) - MastraAuthBetterAuth: 더 나은 인증 통합(
@mastra/auth-better-auth) - 단순 인증: 개발을 위한 토큰-사용자 매핑(
@mastra/core/server)
구현 세부 정보는 소스 코드를 참조하세요.
관련된관련된에 대한 직접 링크
- 인증 개요: 인증 개념 및 구성
- 사용자 정의 API 경로: 사용자 정의 엔드포인트에서 인증 제어