A production-ready, full-stack Next.js application that acts as a secure, multi-tenant proxy and management dashboard for AI providers (OpenAI, OpenRouter, and extensible to others).
- Secure Token-Based Authentication - Issue, revoke, and manage API tokens with scopes and quotas
- Multi-Provider Support - Unified interface for OpenAI, OpenRouter, and custom providers
- Management Dashboard - Full-featured UI for managing endpoints, tokens, providers, and viewing analytics
- Streaming Support - Server-Sent Events (SSE) for real-time chat completions
- Rate Limiting & Quotas - Per-token rate limits and monthly quotas
- Audit Logging - Comprehensive request logging with correlation IDs
- Security - IP whitelisting, token hashing, and strict CORS configuration
- Extensible - Easy to add new providers via adapter pattern
- Frontend: Next.js 14 (App Router) with TypeScript and TailwindCSS
- Backend: Next.js API Routes with provider adapters
- Database: Supabase (PostgreSQL)
- Authentication: Supabase Auth
- Deployment: Vercel-ready
- Node.js 18+ and npm/yarn
- Supabase account and project
- OpenAI API key (optional, for OpenAI provider)
- OpenRouter API key (optional, for OpenRouter provider)
git clone <repository-url>
cd ModelProxy
npm install- Create a new Supabase project at supabase.com
- Run the schema SQL in your Supabase SQL editor:
# Copy and paste the contents of supabase/schema.sql- Get your Supabase credentials:
- Project URL
- Anon key
- Service role key
Create a .env.local file in the root directory:
# Supabase
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# Provider API Keys (optional, can be set per-provider in dashboard)
OPENAI_API_KEY=sk-...
OPENROUTER_API_KEY=sk-or-...
# JWT Secret (generate a random 32+ character string)
JWT_SECRET=your-random-secret-key-here
# App URL (for production)
NEXT_PUBLIC_APP_URL=https://your-domain.vercel.appThe schema is already defined in supabase/schema.sql. Run it in your Supabase SQL editor.
You can manually create providers and endpoints via the dashboard, or use the Supabase dashboard to insert initial data.
npm run devVisit http://localhost:3000
- Go to Supabase Dashboard β Authentication β Users
- Create a new user manually, or enable email signup
- Set the user's role in the
raw_user_meta_datafield:{ "role": "admin" }
- Push your code to GitHub
- Import the project in Vercel
- Add all environment variables in Vercel dashboard
- Deploy
Make sure to set all environment variables in your Vercel project settings.
- Log in at
/login - Navigate to different sections:
- Overview: Dashboard with statistics
- Endpoints: Configure API endpoints and models
- Tokens: Create and manage API tokens
- Providers: Add and configure AI providers
- Usage: View analytics and usage statistics
- Logs: Review request logs
- Go to Providers and add a provider (e.g., OpenAI)
- Go to Endpoints and create a new endpoint:
- Name: e.g., "GPT-4 Chat"
- Path: e.g., "/api/chat"
- Model: e.g., "gpt-4"
- Provider: Select the provider you created
- Go to Tokens
- Click "Create Token"
- Configure:
- Name
- Scopes (chat, embeddings, models, or all)
- Rate limit (requests per minute)
- Monthly quota (optional)
- Copy the token immediately - it won't be shown again!
import { ModelProxyClient } from './sdks/typescript'
const client = new ModelProxyClient('https://your-domain.vercel.app', 'your-token')
// Chat completion
const response = await client.chatCompletion({
endpoint: '/api/chat',
messages: [
{ role: 'user', content: 'Hello!' }
]
})
// Streaming
for await (const chunk of client.chatCompletionStream({
endpoint: '/api/chat',
messages: [{ role: 'user', content: 'Hello!' }]
})) {
console.log(chunk)
}
// Embeddings
const embeddings = await client.embeddings({
endpoint: '/api/embeddings',
input: 'Hello, world!'
})from modelproxy import ModelProxyClient
client = ModelProxyClient('https://your-domain.vercel.app', 'your-token')
# Chat completion
response = client.chat_completion(
endpoint='/api/chat',
messages=[
{'role': 'user', 'content': 'Hello!'}
]
)
# Streaming
for chunk in client.chat_completion_stream(
endpoint='/api/chat',
messages=[{'role': 'user', 'content': 'Hello!'}]
):
print(chunk)
# Embeddings
embeddings = client.embeddings(
endpoint='/api/embeddings',
input='Hello, world!'
)# Chat completion
curl -X POST https://your-domain.vercel.app/api/chat \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "/api/chat",
"messages": [{"role": "user", "content": "Hello!"}]
}'
# Embeddings
curl -X POST https://your-domain.vercel.app/api/embeddings \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "/api/embeddings",
"input": "Hello, world!"
}'Create a chat completion.
Request:
{
"endpoint": "/api/chat",
"messages": [
{ "role": "user", "content": "Hello!" }
],
"stream": false
}Response:
{
"id": "...",
"model": "gpt-4",
"choices": [...]
}Create embeddings.
Request:
{
"endpoint": "/api/embeddings",
"input": "Hello, world!"
}List available models.
Query Parameters:
provider(optional): Filter by provider name
Health check endpoint.
- Create a new provider class implementing
IProviderinterface:
// lib/providers/custom.ts
import type { IProvider, ... } from './types'
export class CustomProvider implements IProvider {
name = 'Custom'
type = 'custom' as const
// Implement required methods
async chatCompletion(...) { ... }
async *chatCompletionStream(...) { ... }
async embeddings(...) { ... }
async listModels(...) { ... }
}- Register it in
lib/providers/factory.ts:
import { CustomProvider } from './custom'
const providers = new Map([
...
['custom', () => new CustomProvider()],
])# Run tests
npm test
# Watch mode
npm run test:watch
# Coverage
npm run test:coverageModelProxy/
βββ app/ # Next.js App Router
β βββ api/ # API routes
β βββ dashboard/ # Dashboard pages
β βββ login/ # Auth pages
βββ components/ # React components
βββ lib/ # Core libraries
β βββ auth/ # Authentication & authorization
β βββ providers/ # Provider adapters
β βββ supabase/ # Supabase clients
β βββ utils/ # Utilities
βββ sdks/ # Client SDKs
β βββ typescript/ # TypeScript SDK
β βββ python/ # Python SDK
βββ supabase/ # Database schema
βββ README.md
- API Keys: Store provider API keys encrypted in the database (consider using Supabase Vault)
- Tokens: Tokens are hashed using bcrypt before storage
- Rate Limiting: Implemented per-token to prevent abuse
- IP Whitelisting: Optional IP-based access control per token
- CORS: Configured for API endpoints
- Audit Logging: All requests are logged with correlation IDs
MIT
Contributions welcome! Please open an issue or submit a pull request.