This example demonstrates how to protect your VoltAgent endpoints with JWT authentication.
- JWT token verification for agent execution endpoints
- User context injection into agent operations
- Role-based access control
- Custom user mapping from JWT claims
- Tools that can access authenticated user information
When JWT authentication is enabled, the following endpoints require a valid token:
POST /agents/:id/text- Generate textPOST /agents/:id/stream- Stream textPOST /agents/:id/object- Generate objectPOST /agents/:id/stream-object- Stream objectPOST /workflows/:id/run- Run workflowPOST /workflows/:id/stream- Stream workflow
These endpoints remain public (no auth required):
GET /agents- List agentsGET /agents/:id- Get agent detailsGET /workflows- List workflowsGET /workflows/:id- Get workflow detailsGET /logs- Get logsGET /- Landing pageGET /doc- API documentationGET /ui- Swagger UI
- Install dependencies:
npm install- Set your JWT secret (optional):
export JWT_SECRET="your-secret-key"npm run devThe server will start and display example JWT tokens for testing.
# Get a token from the console output or create your own
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Make an authenticated request
curl -X POST http://localhost:3141/agents/agent/text \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": "Who am I?"
}'# This will return 401 Unauthorized
curl -X POST http://localhost:3141/agents/agent/text \
-H "Content-Type: application/json" \
-d '{
"messages": "Hello"
}'# These work without authentication
curl http://localhost:3141/agents
curl http://localhost:3141/workflows-
JWT Provider: The
jwtAuthfunction creates an authentication provider that verifies JWT tokens. -
User Mapping: The
mapUserfunction transforms JWT claims into a user object:mapUser: (payload) => ({ id: payload.sub, email: payload.email, name: payload.name, role: payload.role, });
-
Context Injection: The authenticated user is automatically added to the agent's context:
const user = context.context.get("user");
-
Role-Based Access: You can implement custom logic based on user roles:
if (user.role === "admin") { // Admin-only operations }
auth: jwtAuth({
secret: process.env.AUTH0_SECRET,
verifyOptions: {
audience: process.env.AUTH0_AUDIENCE,
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
},
mapUser: (payload) => ({
id: payload.sub,
email: payload.email,
permissions: payload.permissions,
}),
});auth: jwtAuth({
secret: process.env.SUPABASE_JWT_SECRET,
mapUser: (payload) => ({
id: payload.sub,
email: payload.email,
role: payload.role,
metadata: payload.user_metadata,
}),
});auth: jwtAuth({
secret: process.env.CLERK_JWT_KEY,
mapUser: (payload) => ({
id: payload.sub,
email: payload.email,
firstName: payload.first_name,
lastName: payload.last_name,
}),
});- Always use environment variables for JWT secrets in production
- Set appropriate token expiration times
- Use HTTPS in production to protect tokens in transit
- Validate token claims like audience and issuer
- Implement token refresh for long-running sessions
That's it! Your VoltAgent is now protected with JWT authentication. 🔐