Documentation Index Fetch the complete documentation index at: https://docs.leanmcp.com/llms.txt
Use this file to discover all available pages before exploring further.
@leanmcp/auth
Authentication module for LeanMCP providing token-based authentication decorators and multi-provider support for protecting MCP tools, prompts, and resources.
Features
@Authenticated Decorator Protect tools, prompts, and resources with a simple decorator
Multi-Provider Support AWS Cognito, Clerk, Auth0, and LeanMCP providers
Automatic authUser Decoded user info injected as global authUser variable
Concurrency Safe Uses AsyncLocalStorage for request-isolated context
Installation
npm install @leanmcp/auth @leanmcp/core
Provider Dependencies
npm install @aws-sdk/client-cognito-identity-provider axios jsonwebtoken jwk-to-pem
npm install axios jsonwebtoken jwk-to-pem
npm install axios jsonwebtoken jwk-to-pem
Quick Start
1. Initialize Auth Provider
import { AuthProvider } from "@leanmcp/auth" ;
const authProvider = new AuthProvider ( 'cognito' , {
region: 'us-east-1' ,
userPoolId: 'us-east-1_XXXXXXXXX' ,
clientId: 'your-client-id'
});
await authProvider . init ();
2. Protect Methods with @Authenticated
import { Tool } from "@leanmcp/core" ;
import { Authenticated } from "@leanmcp/auth" ;
export class SentimentService {
@ Tool ({ description: 'Analyze sentiment (requires auth)' })
@ Authenticated ( authProvider )
async analyzeSentiment ( input : { text : string }) {
// authUser is automatically available with user info
console . log ( 'User ID:' , authUser . sub );
console . log ( 'Email:' , authUser . email );
return {
sentiment: 'positive' ,
score: 0.8 ,
analyzedBy: authUser . sub
};
}
// Public method - no authentication
@ Tool ({ description: 'Get categories (public)' })
async getCategories () {
return { categories: [ 'positive' , 'negative' , 'neutral' ] };
}
}
3. Protect Entire Service
// All methods in this class require authentication
@ Authenticated ( authProvider )
export class SecureService {
@ Tool ({ description: 'Protected tool' })
async protectedTool ( input : { data : string }) {
// authUser is available in all methods
return { data: input . data , userId: authUser . sub };
}
}
The authUser Variable
When using @Authenticated, a global authUser variable is automatically injected containing the decoded JWT payload:
@ Tool ({ description: 'Create post' })
@ Authenticated ( authProvider )
async createPost ( input : { title: string , content: string }) {
// authUser is automatically available
return {
id: generateId (),
title: input . title ,
content: input . content ,
authorId: authUser . sub ,
authorEmail: authUser . email
};
}
Provider-Specific User Data
{
sub : 'user-uuid' ,
email : 'user@example.com' ,
email_verified : true ,
'cognito:username' : 'username' ,
'cognito:groups' : [ 'admin' , 'users' ]
}
{
sub : 'user_2abc123xyz' ,
userId : 'user_2abc123xyz' ,
email : 'user@example.com' ,
firstName : 'John' ,
lastName : 'Doe' ,
imageUrl : 'https://img.clerk.com/...'
}
{
sub : 'auth0|507f1f77bcf86cd799439011' ,
email : 'user@example.com' ,
email_verified : true ,
name : 'John Doe' ,
picture : 'https://s.gravatar.com/avatar/...'
}
Controlling User Fetch
// Fetch user info (default)
@ Authenticated ( authProvider , { getUser: true })
async withUserInfo ( input : any ) {
console . log ( authUser ); // User data available
}
// Only verify token, skip user fetch (faster)
@ Authenticated ( authProvider , { getUser: false })
async tokenOnlyValidation ( input : any ) {
// authUser is undefined
}
Supported Providers
AWS Cognito
const authProvider = new AuthProvider ( 'cognito' , {
region: 'us-east-1' ,
userPoolId: 'us-east-1_XXXXXXXXX' ,
clientId: 'your-client-id'
});
await authProvider . init ();
Environment Variables:
AWS_REGION = us-east-1
COGNITO_USER_POOL_ID = us-east-1_XXXXXXXXX
COGNITO_CLIENT_ID = your-client-id
Clerk
// Session Mode (default)
const authProvider = new AuthProvider ( 'clerk' , {
frontendApi: 'your-frontend-api.clerk.accounts.dev' ,
secretKey: 'sk_test_...'
});
// OAuth Mode (with refresh tokens)
const authProvider = new AuthProvider ( 'clerk' , {
frontendApi: 'your-frontend-api.clerk.accounts.dev' ,
secretKey: 'sk_test_...' ,
clientId: 'your-oauth-client-id' ,
clientSecret: 'your-oauth-client-secret' ,
redirectUri: 'https://yourapp.com/callback'
});
await authProvider . init ();
Auth0
const authProvider = new AuthProvider ( 'auth0' , {
domain: 'your-tenant.auth0.com' ,
clientId: 'your-client-id' ,
clientSecret: 'your-client-secret' ,
audience: 'https://your-api-identifier'
});
await authProvider . init ();
LeanMCP
For LeanMCP platform deployments with user secrets support:
const authProvider = new AuthProvider ( 'leanmcp' , {
apiKey: 'your-leanmcp-api-key'
});
await authProvider . init ();
Client Usage
Authentication tokens are passed via the _meta field following MCP protocol standards:
await mcpClient . callTool ({
name: "analyzeSentiment" ,
arguments: { text: "Hello world" },
_meta: {
authorization: {
type: "bearer" ,
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
});
Error Handling
import { AuthenticationError } from "@leanmcp/auth" ;
try {
await service . protectedMethod ({ text: "test" });
} catch ( error ) {
if ( error instanceof AuthenticationError ) {
switch ( error . code ) {
case 'MISSING_TOKEN' :
console . log ( 'No token provided' );
break ;
case 'INVALID_TOKEN' :
console . log ( 'Token is invalid or expired' );
break ;
case 'VERIFICATION_FAILED' :
console . log ( 'Verification failed:' , error . message );
break ;
}
}
}
API Reference
AuthProvider
class AuthProvider {
constructor ( provider : string , config : any );
async init ( config ?: any ) : Promise < void >;
async verifyToken ( token : string ) : Promise < boolean >;
async refreshToken ( refreshToken : string ) : Promise < any >;
async getUser ( token : string ) : Promise < any >;
getProviderType () : string ;
}
@Authenticated Decorator
function Authenticated (
authProvider : AuthProvider ,
options ?: AuthenticatedOptions
) : ClassDecorator | MethodDecorator ;
interface AuthenticatedOptions {
getUser ?: boolean ; // Default: true
projectId ?: string ; // For LeanMCP user secrets
}
AuthenticationError
class AuthenticationError extends Error {
code : 'MISSING_TOKEN' | 'INVALID_TOKEN' | 'VERIFICATION_FAILED' ;
constructor ( message : string , code : string );
}
Helper Functions
// Check if authentication is required
function isAuthenticationRequired ( target : any ) : boolean ;
// Get auth provider for method/class
function getAuthProvider ( target : any ) : AuthProviderBase | undefined ;
// Get current authenticated user
function getAuthUser () : any ;
Best Practices
Always use HTTPS in production
Store tokens securely (keychain, encrypted storage)
Implement token refresh before expiration
Add rate limiting to protect against brute force
Use environment variables for credentials
Never hardcode secrets in code
Use _meta for auth, not business arguments
OAuth 2.1 Support
Beyond server-side token verification, @leanmcp/auth provides complete OAuth 2.1 infrastructure:
OAuth Client Browser-based OAuth flows with PKCE, token storage, and automatic refresh
OAuth Server & Proxy Build authorization servers with external provider proxy support
Submodule Imports
// Server-side token verification (this page)
import { AuthProvider , Authenticated } from '@leanmcp/auth' ;
// OAuth client for browser-based flows
import { OAuthClient } from '@leanmcp/auth/client' ;
// Token storage backends
import { MemoryStorage , FileStorage , KeychainStorage } from '@leanmcp/auth/storage' ;
// OAuth proxy for external providers
import { OAuthProxy , googleProvider , githubProvider } from '@leanmcp/auth/proxy' ;
// OAuth authorization server
import { OAuthAuthorizationServer } from '@leanmcp/auth/server' ;
Links