Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

mcpresso-oauth-server

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mcpresso-oauth-server

Production-ready OAuth 2.1 server implementation for Model Context Protocol (MCP) with PKCE support

latest
Source
npmnpm
Version
1.2.17
Version published
Weekly downloads
20
122.22%
Maintainers
1
Weekly downloads
 
Created
Source

mcpresso-oauth-server

A production-ready OAuth 2.1 server implementation designed specifically for Model Context Protocol (MCP) servers. Provides seamless authentication integration with mcpresso servers.

Features

  • OAuth 2.1 Compliant - Full implementation of OAuth 2.1 draft specification
  • MCP Integration - Designed specifically for Model Context Protocol
  • PKCE Support - Proof Key for Code Exchange (required for MCP)
  • Custom User Authentication - Pluggable login logic and UI customization
  • Production Ready - Security headers, rate limiting, compression, CORS
  • Flexible Deployment - Run standalone or integrated with MCP servers
  • Dynamic Client Registration - RFC 7591 compliant
  • Multiple Grant Types - Authorization code, refresh token, client credentials
  • Token Introspection - RFC 7662 compliant
  • Discovery Endpoints - RFC 8414 and RFC 9728 compliant

Quick Start

Installation

npm install mcpresso-oauth-server
# or
bun add mcpresso-oauth-server

Basic Usage

import { 
  MCPOAuthServer, 
  MemoryStorage 
} from 'mcpresso-oauth-server'

// Initialize storage with demo data
const storage = new MemoryStorage()
await storage.createClient({
  id: 'demo-client',
  secret: 'demo-secret',
  name: 'Demo Client',
  type: 'confidential',
  redirectUris: ['http://localhost:4000/callback'],
  scopes: ['read', 'write'],
  grantTypes: ['authorization_code']
})

// Create OAuth server with custom authentication
const oauthServer = new MCPOAuthServer({
  issuer: 'http://localhost:4000',
  serverUrl: 'http://localhost:4000',
  jwtSecret: 'your-secret-key',
  auth: {
    authenticateUser: async (credentials, context) => {
      // Your login logic here
      const user = users.find(u => u.username === credentials.username)
      return user && validatePassword(credentials.password, user.password) ? user : null
    },
    getCurrentUser: async (sessionData, context) => {
      // Check if user is already logged in via session/cookies
      return null // Force login for this example
    },
    renderLoginPage: async (context, error) => {
      // Optional: Customize login page
      return `<html>...custom login form...</html>`
    }
  }
}, storage)

MCP Integration

Two Deployment Modes

Mode 1: Integrated (Same Port)

Run OAuth and MCP server together:

import { createMCPServer } from 'mcpresso'
import { MCPOAuthServer } from 'mcpresso-oauth-server'

// Create OAuth server
const oauthServer = new MCPOAuthServer({...}, storage)

// Create MCP server with integrated OAuth
const app = createMCPServer({
  name: "integrated_server",
  resources: [userResource],
  auth: {
    oauth: oauthServer,              // Integrate OAuth server
    userLookup: async (jwtPayload) => {
      // Fetch full user profiles from your database
      return await db.users.findById(jwtPayload.sub)
    }
  }
})

app.listen(4000) // Both OAuth and MCP on port 4000

Architecture:

┌─────────────────────────────────┐
│        Integrated Server        │
│         (Port 4000)             │
│                                 │
│ ┌─────────────┐ ┌─────────────┐ │
│ │OAuth Service│ │ MCP Service │ │
│ │• /authorize │ │• MCP API    │ │
│ │• /token     │ │• Resources  │ │
│ │• Login UI   │ │• Tools      │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────┘

Mode 2: Separate Servers

Run OAuth and MCP on different ports:

// OAuth Server (Port 4001)
const oauthApp = express()
oauthApp.use(cors()) // Important for cross-origin requests
registerOAuthEndpoints(oauthApp, oauthServer)
oauthApp.listen(4001)

// MCP Server (Port 4000)
const mcpApp = createMCPServer({
  name: "api_server",
  resources: [userResource],
  auth: {
    issuer: "http://localhost:4001",      // OAuth server URL
    serverUrl: "http://localhost:4000",   // This MCP server URL
    jwtSecret: "shared-secret",           // Same secret as OAuth server
    userLookup: async (jwtPayload) => {
      return await db.users.findById(jwtPayload.sub)
    }
  }
})
mcpApp.listen(4000)

Architecture:

┌─────────────────┐    ┌──────────────────┐
│   OAuth Server  │    │    MCP Server    │
│   (Port 4001)   │    │   (Port 4000)    │
│                 │    │                  │
│ • /authorize    │    │ • MCP API        │
│ • /token        │    │ • Token Validation│
│ • Login UI      │    │ • Resources      │
└─────────────────┘    └──────────────────┘

Custom Authentication

User Authentication Callbacks

Implement your own user authentication logic:

const oauthServer = new MCPOAuthServer({
  // ... other config
  auth: {
    // Required: Validate user credentials
    authenticateUser: async (credentials, context) => {
      const { username, password } = credentials
      
      // Example with database lookup
      const user = await db.users.findByEmail(username)
      if (!user) return null
      
      // Verify password (use bcrypt in production)
      const isValid = await bcrypt.compare(password, user.hashedPassword)
      if (!isValid) return null
      
      // Return user object
      return {
        id: user.id,
        username: user.email,
        email: user.email,
        scopes: user.permissions // e.g., ['read', 'write', 'admin']
      }
    },
    
    // Optional: Check existing sessions
    getCurrentUser: async (sessionData, context) => {
      if (sessionData?.userId) {
        return await db.users.findById(sessionData.userId)
      }
      return null
    },
    
    // Optional: Custom login page
    renderLoginPage: async (context, error) => {
      return `
        <!DOCTYPE html>
        <html>
          <head><title>Login - ${context.clientId}</title></head>
          <body>
            <h2>Login to ${context.clientId}</h2>
            ${error ? `<p style="color:red">${error}</p>` : ''}
            <form method="POST" action="/authorize">
              <!-- Hidden OAuth parameters -->
              <input type="hidden" name="response_type" value="code">
              <input type="hidden" name="client_id" value="${context.clientId}">
              <input type="hidden" name="redirect_uri" value="${context.redirectUri}">
              <input type="hidden" name="scope" value="${context.scope || ''}">
              
              <!-- Login form -->
              <div>
                <label>Email:</label>
                <input type="email" name="username" required>
              </div>
              <div>
                <label>Password:</label>
                <input type="password" name="password" required>
              </div>
              <button type="submit">Login</button>
            </form>
          </body>
        </html>
      `
    }
  }
}, storage)

Integration Examples

With Supabase

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(url, key)

const oauthServer = new MCPOAuthServer({
  auth: {
    authenticateUser: async ({ username, password }) => {
      const { data, error } = await supabase.auth.signInWithPassword({
        email: username,
        password: password
      })
      
      if (error || !data.user) return null
      
      return {
        id: data.user.id,
        username: data.user.email,
        email: data.user.email,
        scopes: data.user.user_metadata?.scopes || ['read']
      }
    }
  }
})

With Firebase

import { signInWithEmailAndPassword } from 'firebase/auth'

const oauthServer = new MCPOAuthServer({
  auth: {
    authenticateUser: async ({ username, password }) => {
      try {
        const userCredential = await signInWithEmailAndPassword(auth, username, password)
        const user = userCredential.user
        
        return {
          id: user.uid,
          username: user.email,
          email: user.email,
          scopes: user.customClaims?.scopes || ['read']
        }
      } catch (error) {
        return null
      }
    }
  }
})

Configuration

Environment Variables

Configure the server using environment variables:

# Server configuration
OAUTH_ISSUER=https://auth.yourdomain.com
OAUTH_SERVER_URL=https://auth.yourdomain.com
OAUTH_JWT_SECRET=your-super-secret-jwt-key

# CORS configuration (for separate server deployment)
CORS_ORIGIN=https://yourdomain.com,https://api.yourdomain.com
TRUST_PROXY=true

# Server port
PORT=4001

Security Configuration

The server includes production-ready security features:

const oauthServer = new MCPOAuthServer({
  // ... OAuth config
  http: {
    cors: {
      origin: ['https://yourdomain.com'],
      credentials: true,
      methods: ['GET', 'POST', 'OPTIONS']
    },
    enableHelmet: true,
    enableRateLimit: true,
    rateLimitConfig: {
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100 // requests per window
    }
  }
})

API Endpoints

OAuth 2.1 Endpoints

  • GET /authorize - Authorization endpoint (shows login page)
  • POST /authorize - Authorization endpoint (processes login)
  • POST /token - Token endpoint
  • POST /introspect - Token introspection
  • POST /revoke - Token revocation
  • GET /userinfo - User info endpoint
  • POST /register - Dynamic client registration

Discovery Endpoints

  • GET /.well-known/oauth-authorization-server - OAuth metadata (RFC 8414)
  • GET /.well-known/jwks.json - JSON Web Key Set
  • GET /.well-known/oauth-protected-resource - MCP protected resource metadata

Admin Endpoints

  • GET /health - Health check
  • GET /admin/clients - List clients
  • GET /admin/users - List users
  • GET /admin/stats - Server statistics

Storage

The package includes an in-memory storage implementation for development. For production, implement the MCPOAuthStorage interface:

import type { MCPOAuthStorage } from 'mcpresso-oauth-server'

class DatabaseStorage implements MCPOAuthStorage {
  async createClient(client: OAuthClient): Promise<void> {
    // Store client in your database
  }
  
  async getClient(clientId: string): Promise<OAuthClient | null> {
    // Fetch client from your database
  }
  
  // ... implement all required methods
}

Examples

See complete working examples:

  • Integrated OAuth: mcpresso/examples/oauth2-simple-demo.ts
  • Separate Servers: mcpresso/examples/separate-servers-demo.ts

Testing

Manual OAuth Flow Testing

  • Get Authorization Code:
# Open in browser or use curl
curl "http://localhost:4001/authorize?response_type=code&client_id=demo-client&redirect_uri=http://localhost:4001/callback&scope=read&resource=http://localhost:4000"
  • Exchange for Token:
curl -X POST "http://localhost:4001/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&client_id=demo-client&client_secret=demo-secret&code=YOUR_CODE&redirect_uri=http://localhost:4001/callback&resource=http://localhost:4000"
  • Use Token with MCP API:
curl -X POST "http://localhost:4000" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"whoami_user","arguments":{}}}'

Development

Build & Test

# Install dependencies
bun install

# Build the package
bun run build

# Run tests
bun test

# Start development server
bun run dev

Security Best Practices

For production deployments:

  • Use Strong JWT Secrets - Generate cryptographically secure secrets
  • Configure CORS Properly - Only allow trusted origins
  • Enable HTTPS - Always use HTTPS in production
  • Implement Proper Storage - Use a production database, not memory storage
  • Monitor & Log - Set up proper logging and monitoring
  • Keep Dependencies Updated - Regularly update packages
  • Rate Limiting - Configure appropriate rate limits
  • Input Validation - Validate all user inputs

Support

License

MIT - See LICENSE file for details.

Keywords

oauth2

FAQs

Package last updated on 01 Sep 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts