MastraAuthBetterAuth Class
The MastraAuthBetterAuth class provides authentication for Mastra using Better Auth. It verifies incoming requests using your Better Auth instance and integrates with the Mastra server via the server.auth option.
PrerequisitesDirect link to Prerequisites
This example uses Better Auth. Make sure your Better Auth instance is configured and your environment variables are set.
# Required by Better Auth
BETTER_AUTH_SECRET=... # at least 32 chars
BETTER_AUTH_URL=http://localhost:3000
# Example DB URL used by the snippet below (adjust for your setup)
DATABASE_URL=postgres://...
Better Auth recommends setting baseURL explicitly (or via BETTER_AUTH_URL) for security and stability.
If you haven't mounted Better Auth's handler yet (so your app can sign users in / create sessions), follow the Better Auth installation guide to mount the /api/auth/* route (or your configured base path).
InstallationDirect link to Installation
Install the @mastra/auth-better-auth package:
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/auth-better-auth
pnpm add @mastra/auth-better-auth
yarn add @mastra/auth-better-auth
bun add @mastra/auth-better-auth
Usage exampleDirect link to Usage example
First, create your Better Auth instance:
import { betterAuth } from 'better-auth'
export const auth = betterAuth({
database: {
provider: 'postgresql',
url: process.env.DATABASE_URL!,
},
emailAndPassword: {
enabled: true,
},
baseURL: process.env.BETTER_AUTH_URL,
secret: process.env.BETTER_AUTH_SECRET,
})
Then, use it with Mastra:
import { Mastra } from '@mastra/core'
import { MastraAuthBetterAuth } from '@mastra/auth-better-auth'
import { auth } from '@/lib/auth'
const mastraAuth = new MastraAuthBetterAuth({
auth,
})
export const mastra = new Mastra({
server: {
auth: mastraAuth,
},
})
Visit MastraAuthBetterAuth for all available configuration options.
Custom authorizationDirect link to Custom authorization
const mastraAuth = new MastraAuthBetterAuth({
auth,
async authorizeUser(user) {
// Example: only allow verified emails
return user?.user?.emailVerified === true
},
})
Route configurationDirect link to Route configuration
const mastraAuth = new MastraAuthBetterAuth({
auth,
public: ['/health', '/api/status'],
protected: ['/api/*', '/admin/*'],
})
Matching rulesDirect link to Matching rules
publicandprotectedaccept exact paths, wildcard patterns (like/api/*), and path params (like/users/:id).- For method-specific rules, use tuples like
["/api/agents", ["GET", "POST"]]. - If a route matches both
publicandprotected,publicwins and no auth is required. - If neither matches, routes are treated as protected by default (unless a route is explicitly marked
requiresAuth: false).
Client-side setupDirect link to Client-side setup
When auth is enabled, requests to Mastra's built-in routes require authentication. In practice, that means your client needs to send whatever credential your Better Auth setup uses for authenticated requests.
Cookie session (recommended)Direct link to Cookie session (recommended)
If your Better Auth setup uses cookies, configure the client to send credentials. For cross-origin requests (e.g. Next.js on :3000 calling Mastra on :4111), enable CORS credentials on the Mastra server:
export const mastra = new Mastra({
server: {
auth: mastraAuth,
cors: {
origin: 'http://localhost:3000', // your frontend origin
credentials: true,
},
},
})
Then configure the client to include credentials:
import { MastraClient } from '@mastra/client-js'
export const mastraClient = new MastraClient({
baseUrl: 'http://localhost:4111',
credentials: 'include',
})
If you are calling the API directly, include credentials in fetch as well:
await fetch('http://localhost:4111/api/agents/weatherAgent/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({ messages: 'Weather in London' }),
})
Bearer tokenDirect link to Bearer token
You can pass the signed session token as a Bearer token. Retrieve it from your Better Auth client session and include it in the Authorization header:
import { MastraClient } from '@mastra/client-js'
import { authClient } from './auth-client' // your Better Auth client
const session = await authClient.getSession()
export const mastraClient = new MastraClient({
baseUrl: 'http://localhost:4111',
headers: {
Authorization: `Bearer ${session.data?.session.token}`,
},
})
Visit Mastra Client SDK for more configuration options.
Making authenticated requestsDirect link to Making authenticated requests
- React
- cURL
import { mastraClient } from '../lib/mastra-client'
export const TestAgent = () => {
async function handleClick() {
const agent = mastraClient.getAgent('weatherAgent')
const response = await agent.generate('Weather in London')
console.log(response)
}
return <button onClick={handleClick}>Test Agent</button>
}
curl -X POST http://localhost:4111/api/agents/weatherAgent/generate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"messages": "Weather in London"
}'
TroubleshootingDirect link to Troubleshooting
- 401 on every request: confirm your Better Auth handler is mounted and your app can create a valid session. Check that your client sends either a session cookie or an
Authorization: Bearer <signed-token>header. - Cookies not sent cross-origin: set
credentials: "include"inMastraClientand configureserver.corswith your frontend origin andcredentials: true. - Bearer token rejected: ensure you pass the full signed session token (from
authClient.getSession()), not a raw or unsigned token. - Base URL issues: set
baseURLinbetterAuth({ ... })or setBETTER_AUTH_URL. - DB connection errors: verify
DATABASE_URLand database provider configuration.