Skip to content

Commit 9aa55c4

Browse files
rphansen91claude
andauthored
docs(auth): add SimpleAuth and Custom Auth Provider documentation (#12374)
## Summary - Add documentation for **SimpleAuth**: built-in token-to-user mapping provider for development and simple API key authentication - Add documentation for **CompositeAuth**: combine multiple auth providers into a single handler (e.g., support both API keys and OAuth) - Add documentation for **Custom Auth Provider**: guide for creating custom authentication providers by extending `MastraAuthProvider` - Update **Auth Overview** page to organize providers into categories (Built-in, Third-party, Advanced) - Update sidebar to include all new documentation pages These documentation gaps were identified during conversations with the team at Indeed. ## Test plan - [ ] Verify docs build successfully - [ ] Check SimpleAuth doc renders correctly at `/docs/server/auth/simple-auth` - [ ] Check CompositeAuth doc renders correctly at `/docs/server/auth/composite-auth` - [ ] Check Custom Auth Provider doc renders correctly at `/docs/server/auth/custom-auth-provider` - [ ] Check Auth Overview shows organized provider categories at `/docs/server/auth` - [ ] Verify sidebar navigation works correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added guides for SimpleAuth and CompositeAuth authentication methods * Introduced documentation for implementing custom authentication providers * Reorganized authentication documentation into Built-in, Third-party integrations, and Advanced categories * Updated navigation to include new authentication documentation sections <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ae3e0f8 commit 9aa55c4

File tree

5 files changed

+973
-1
lines changed

5 files changed

+973
-1
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
---
2+
title: "CompositeAuth Class | Auth"
3+
description: "Documentation for the CompositeAuth class, which combines multiple authentication providers into a single auth handler."
4+
packages:
5+
- "@mastra/core"
6+
---
7+
8+
# CompositeAuth Class
9+
10+
The `CompositeAuth` class allows you to combine multiple authentication providers into a single auth handler. It tries each provider in order until one succeeds.
11+
12+
## Use Cases
13+
14+
- Support both API keys and OAuth tokens
15+
- Migrate between auth providers without breaking existing clients
16+
- Allow multiple identity providers (e.g., Clerk for web, API keys for integrations)
17+
- Gradual rollout of new authentication methods
18+
19+
## Installation
20+
21+
CompositeAuth is included in `@mastra/core`, no additional packages required.
22+
23+
```typescript
24+
import { CompositeAuth } from '@mastra/core/server';
25+
```
26+
27+
## Usage Example
28+
29+
Combine SimpleAuth (for API keys) with Clerk (for user sessions):
30+
31+
```typescript title="src/mastra/index.ts"
32+
import { Mastra } from '@mastra/core';
33+
import { CompositeAuth, SimpleAuth } from '@mastra/core/server';
34+
import { MastraAuthClerk } from '@mastra/auth-clerk';
35+
36+
// API key users
37+
type ApiKeyUser = {
38+
id: string;
39+
name: string;
40+
type: 'api-key';
41+
};
42+
43+
const apiKeyAuth = new SimpleAuth<ApiKeyUser>({
44+
tokens: {
45+
'sk-integration-key-123': {
46+
id: 'integration-1',
47+
name: 'CI/CD Pipeline',
48+
type: 'api-key',
49+
},
50+
},
51+
});
52+
53+
// Clerk users (from web app)
54+
const clerkAuth = new MastraAuthClerk({
55+
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
56+
secretKey: process.env.CLERK_SECRET_KEY,
57+
jwksUri: process.env.CLERK_JWKS_URI,
58+
});
59+
60+
export const mastra = new Mastra({
61+
server: {
62+
auth: new CompositeAuth([apiKeyAuth, clerkAuth]),
63+
},
64+
});
65+
```
66+
67+
## How It Works
68+
69+
When a request comes in, CompositeAuth:
70+
71+
1. Extracts the token from the `Authorization` header
72+
2. Tries each provider's `authenticateToken()` method in order
73+
3. Returns the user from the first provider that succeeds
74+
4. Returns `null` (401 Unauthorized) if all providers fail
75+
76+
For authorization, it calls each provider's `authorizeUser()` method until one returns `true`.
77+
78+
```typescript
79+
// Pseudocode of CompositeAuth behavior
80+
async authenticateToken(token, request) {
81+
for (const provider of this.providers) {
82+
const user = await provider.authenticateToken(token, request);
83+
if (user) return user; // First match wins
84+
}
85+
return null; // All providers failed
86+
}
87+
```
88+
89+
## Provider Order
90+
91+
The order of providers matters. Place the most common authentication method first for better performance:
92+
93+
```typescript
94+
// If most requests use Clerk, put it first
95+
new CompositeAuth([
96+
clerkAuth, // Checked first (most common)
97+
apiKeyAuth, // Checked second (less common)
98+
]);
99+
100+
// If most requests use API keys, put it first
101+
new CompositeAuth([
102+
apiKeyAuth, // Checked first (most common)
103+
clerkAuth, // Checked second (less common)
104+
]);
105+
```
106+
107+
## Multiple OAuth Providers
108+
109+
Support users from different identity providers:
110+
111+
```typescript
112+
import { CompositeAuth } from '@mastra/core/server';
113+
import { MastraAuthClerk } from '@mastra/auth-clerk';
114+
import { MastraAuthAuth0 } from '@mastra/auth-auth0';
115+
116+
const clerkAuth = new MastraAuthClerk({
117+
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
118+
secretKey: process.env.CLERK_SECRET_KEY,
119+
jwksUri: process.env.CLERK_JWKS_URI,
120+
});
121+
122+
const auth0Auth = new MastraAuthAuth0({
123+
domain: process.env.AUTH0_DOMAIN,
124+
audience: process.env.AUTH0_AUDIENCE,
125+
});
126+
127+
export const mastra = new Mastra({
128+
server: {
129+
auth: new CompositeAuth([clerkAuth, auth0Auth]),
130+
},
131+
});
132+
```
133+
134+
## Migration Example
135+
136+
Migrate from JWT to Clerk while maintaining backwards compatibility:
137+
138+
```typescript
139+
import { CompositeAuth } from '@mastra/core/server';
140+
import { MastraJwtAuth } from '@mastra/auth';
141+
import { MastraAuthClerk } from '@mastra/auth-clerk';
142+
143+
// Legacy JWT auth (existing clients)
144+
const legacyAuth = new MastraJwtAuth({
145+
secret: process.env.JWT_SECRET,
146+
});
147+
148+
// New Clerk auth (new clients)
149+
const clerkAuth = new MastraAuthClerk({
150+
publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
151+
secretKey: process.env.CLERK_SECRET_KEY,
152+
jwksUri: process.env.CLERK_JWKS_URI,
153+
});
154+
155+
// Support both during migration
156+
export const mastra = new Mastra({
157+
server: {
158+
auth: new CompositeAuth([
159+
clerkAuth, // New auth method (preferred)
160+
legacyAuth, // Legacy support
161+
]),
162+
},
163+
});
164+
```
165+
166+
## With Custom Providers
167+
168+
Combine built-in providers with custom implementations:
169+
170+
```typescript
171+
import { CompositeAuth, SimpleAuth } from '@mastra/core/server';
172+
import { MyCustomAuth } from './my-custom-auth';
173+
174+
const apiKeyAuth = new SimpleAuth({
175+
tokens: {
176+
'sk-key-123': { id: 'user-1', name: 'API User' },
177+
},
178+
});
179+
180+
const customAuth = new MyCustomAuth({
181+
apiUrl: process.env.CUSTOM_AUTH_URL,
182+
});
183+
184+
export const mastra = new Mastra({
185+
server: {
186+
auth: new CompositeAuth([apiKeyAuth, customAuth]),
187+
},
188+
});
189+
```
190+
191+
## Error Handling
192+
193+
CompositeAuth silently catches errors from individual providers and moves to the next one. This prevents one failing provider from blocking authentication:
194+
195+
```typescript
196+
// If clerkAuth throws an error, apiKeyAuth still gets tried
197+
new CompositeAuth([clerkAuth, apiKeyAuth]);
198+
```
199+
200+
To debug authentication issues, add logging to your custom providers or check individual provider configurations.
201+
202+
## Limitations
203+
204+
- All providers share the same token from the `Authorization` header
205+
- User types may differ between providers (use discriminated unions if needed)
206+
- No built-in way to identify which provider authenticated a request
207+
208+
### Handling Different User Types
209+
210+
When providers return different user types, use a discriminated union:
211+
212+
```typescript
213+
type ApiKeyUser = {
214+
type: 'api-key';
215+
id: string;
216+
name: string;
217+
};
218+
219+
type ClerkUser = {
220+
type: 'clerk';
221+
sub: string;
222+
email: string;
223+
};
224+
225+
type User = ApiKeyUser | ClerkUser;
226+
227+
// In your application code
228+
function handleUser(user: User) {
229+
if (user.type === 'api-key') {
230+
console.log('API key user:', user.name);
231+
} else {
232+
console.log('Clerk user:', user.email);
233+
}
234+
}
235+
```
236+
237+
## Related
238+
239+
- [Auth Overview](/docs/server/auth) - Authentication concepts
240+
- [Simple Auth](/docs/server/auth/simple-auth) - Token-to-user mapping
241+
- [Custom Auth Provider](/docs/server/auth/custom-auth-provider) - Build your own provider

0 commit comments

Comments
 (0)