Skip to main content
Glama
README.md7.34 kB
# Example 09: Auth0 Authentication This example demonstrates how to integrate Auth0 authentication with Express-MCP, including JWT validation, permission-based access control, and OAuth2 scopes. > **Note**: This example uses mock tokens for demonstration. In production, integrate with actual Auth0 using `express-jwt`, `jwks-rsa`, and Auth0 SDK. ## Features - **JWT Validation**: Verify Auth0-issued JWTs - **Permission-based Access**: Fine-grained permissions - **OAuth2 Scopes**: Scope-based authorization - **User Management**: Auth0 user profile integration - **Token Passthrough**: Maintain auth through MCP layer ## Running the Example ```bash # Install dependencies pnpm install # Run the example pnpm tsx examples/09-auth0/server.ts ``` ## Auth0 Setup (Production) 1. **Create Auth0 Application**: - Go to Auth0 Dashboard > Applications - Create a new Single Page Application - Note the Domain, Client ID, and Client Secret 2. **Configure API**: - Go to APIs > Create API - Set identifier (audience): `https://your-api.example.com` - Enable RBAC and Add Permissions in Token 3. **Define Permissions**: - `read:profile` - Read user profile - `write:profile` - Update user profile - `read:users` - List users - `write:users` - Create/update users - `admin:all` - Admin access 4. **Environment Variables**: ```env AUTH0_DOMAIN=your-tenant.auth0.com AUTH0_AUDIENCE=https://your-api.example.com AUTH0_CLIENT_ID=your-client-id AUTH0_CLIENT_SECRET=your-client-secret ``` ## Authentication Flow ### 1. Login ```bash curl -X POST http://localhost:3009/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "password" }' ``` Response: ```json { "access_token": "mock-jwt-user", "token_type": "Bearer", "expires_in": 3600, "user": { "sub": "auth0|user123", "email": "user@example.com", "name": "John Doe" } } ``` ### 2. Use Token ```bash curl http://localhost:3009/api/profile \ -H "Authorization: Bearer mock-jwt-user" ``` ### 3. MCP with Auth0 ```bash curl -X POST http://localhost:3009/mcp/invoke \ -H "Content-Type: application/json" \ -H "Authorization: Bearer mock-jwt-user" \ -d '{ "toolName": "GET_/api/profile", "args": {} }' ``` ## Permission Model ### User Roles and Permissions | Role | Permissions | Access | |------|------------|--------| | User | `read:profile`, `write:profile` | Own profile | | Admin | All permissions + `admin:all` | Everything | | Viewer | `read:profile`, `read:users` | Read-only | ### Testing Permissions ```bash # User can read their profile curl -H "Authorization: Bearer mock-jwt-user" \ http://localhost:3009/api/profile # User cannot access admin endpoints curl -H "Authorization: Bearer mock-jwt-user" \ http://localhost:3009/api/admin/users # Returns: 403 Forbidden # Admin can access everything curl -H "Authorization: Bearer mock-jwt-admin" \ http://localhost:3009/api/admin/users # Returns: 200 OK ``` ## OAuth2 Scopes ### Scope-based Access ```bash # Requires 'email' scope curl http://localhost:3009/api/email \ -H "Authorization: Bearer mock-jwt-user" ``` ### Available Scopes - `openid` - OpenID Connect - `profile` - User profile information - `email` - Email address - `offline_access` - Refresh tokens ## Production Implementation ### 1. Install Dependencies ```bash pnpm add express-jwt jwks-rsa auth0 ``` ### 2. JWT Middleware ```typescript import { expressjwt } from "express-jwt"; import jwksRsa from "jwks-rsa"; const checkJwt = expressjwt({ secret: jwksRsa.expressJwtSecret({ cache: true, rateLimit: true, jwksRequestsPerMinute: 5, jwksUri: `https://${AUTH0_DOMAIN}/.well-known/jwks.json` }), audience: AUTH0_AUDIENCE, issuer: `https://${AUTH0_DOMAIN}/`, algorithms: ["RS256"] }); ``` ### 3. Permission Check ```typescript const checkPermission = (permission: string) => { return (req, res, next) => { const { permissions } = req.auth; if (!permissions?.includes(permission)) { return res.status(403).json({ error: "Insufficient permissions" }); } next(); }; }; ``` ### 4. User Info ```typescript import { ManagementClient } from "auth0"; const management = new ManagementClient({ domain: AUTH0_DOMAIN, clientId: AUTH0_CLIENT_ID, clientSecret: AUTH0_CLIENT_SECRET, }); app.get("/api/user/:id", checkJwt, async (req, res) => { const user = await management.getUser({ id: req.params.id }); res.json(user); }); ``` ## MCP Integration ### Passing Auth0 Tokens ```typescript // MCP invoke with Auth0 token app.post("/mcp/invoke", async (req, res) => { const authHeader = req.headers.authorization; // Pass token to underlying routes const headers = { authorization: authHeader, }; const result = await dispatcher.dispatch( route.method, route.path, args, headers ); }); ``` ### Protected MCP Tools Tools automatically inherit Auth0 protection: ```bash # Public tool - works without auth curl -X POST http://localhost:3009/mcp/invoke \ -d '{"toolName": "GET_/", "args": {}}' # Protected tool - requires valid JWT curl -X POST http://localhost:3009/mcp/invoke \ -H "Authorization: Bearer mock-jwt-user" \ -d '{"toolName": "GET_/api/profile", "args": {}}' ``` ## Testing Scenarios ### Successful Flow ```bash # 1. Login TOKEN=$(curl -s -X POST http://localhost:3009/auth/login \ -H "Content-Type: application/json" \ -d '{"email": "admin@example.com", "password": "admin"}' \ | jq -r .access_token) # 2. Access protected endpoint curl http://localhost:3009/api/profile \ -H "Authorization: Bearer $TOKEN" # 3. Invoke MCP tool curl -X POST http://localhost:3009/mcp/invoke \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{"toolName": "GET_/api/admin/users", "args": {}}' ``` ### Error Scenarios ```bash # No token curl http://localhost:3009/api/profile # 401: No token provided # Invalid token curl http://localhost:3009/api/profile \ -H "Authorization: Bearer invalid" # 401: Invalid token # Insufficient permissions curl http://localhost:3009/api/admin/users \ -H "Authorization: Bearer mock-jwt-user" # 403: Permission 'admin:all' required ``` ## Security Best Practices 1. **Always Use HTTPS**: Protect tokens in transit 2. **Validate Tokens**: Verify signature and claims 3. **Check Permissions**: Enforce at API level 4. **Token Expiry**: Implement short-lived tokens 5. **Refresh Tokens**: Use refresh token rotation 6. **Audit Logging**: Log all auth events 7. **Rate Limiting**: Prevent token abuse ## Troubleshooting ### Common Issues 1. **Token Expired**: - Get a new token via login - Implement refresh token flow 2. **Invalid Audience**: - Check AUTH0_AUDIENCE matches API identifier - Verify token was issued for correct API 3. **Missing Permissions**: - Check user's assigned permissions in Auth0 - Verify permissions are included in token 4. **CORS Issues**: - Configure CORS for your domain - Add Auth0 domain to allowed origins ## Next Steps - Implement refresh token flow - Add user registration via Auth0 - Configure social login providers - Set up Auth0 Rules for custom claims - Implement MFA (Multi-Factor Authentication) - Add Auth0 Actions for custom logic

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bowen31337/expressjs_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server