AI-generated and human-reviewed news meta-commentary
Development › Software Engineering
,
Security › Authentication
Building Supabase-like OAuth Authentication For MCP Servers
Learn how to implement OAuth2 authentication with dynamic client registration and authorization server metadata for MCP servers using a reverse proxy gateway approach.
Signal Editorial Team
AI-generated and human-reviewed news meta-commentary
4 minute read
Building Supabase-like OAuth Authentication For MCP Servers
MCP servers need OAuth2 authentication to work securely in production environments. The Model Context Protocol specification requires OAuth2 with Dynamic Client Registration (DCR) and Authorization Server Metadata (ASM) extensions - features most identity providers don’t support.
This guide shows you how to build a reverse proxy gateway that adds OAuth2 authentication to existing MCP servers without modifying their code.
The Authentication Challenge
The MCP authorization framework builds on OAuth2 2.1 draft specification with three required extensions:
Authorization Server Metadata (ASM) - Discovers OAuth2 endpoints
Protected Resource Server (PRS) - Validates access tokens
Most identity providers support OAuth2 but lack these extensions. Here’s what we found:
Provider
DCR Support
ASM Support
CORS Support
OAuth2-Proxy
❌
❌
❌
Dex
❌ (gRPC only)
⚠️ (OIDC only)
❌
Keycloak
✅
✅
⚠️ (not for DCR)
Gateway Architecture
The solution uses a reverse proxy that sits between MCP clients and servers. The gateway handles authentication while forwarding requests to upstream MCP servers unchanged.
MCP Client → Gateway (Auth) → MCP Server
We’ll use Dex as the identity provider and implement missing OAuth2 extensions through its gRPC API.
Protect the proxy endpoint by validating JWT access tokens:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
funcOAuthProtected(nexthttp.Handler)http.Handler{varjwkSetjwk.Set// Load from your identity providerreturnhttp.HandlerFunc(func(whttp.ResponseWriter,r*http.Request){rawToken:=strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(r.Header.Get("Authorization")),"Bearer"))if_,err:=jwt.ParseString(rawToken,jwt.WithKeySet(jwkSet));err!=nil{w.Header().Set("WWW-Authenticate",`Bearer resource_metadata="http://localhost:9000/.well-known/oauth-protected-resource"`)w.WriteHeader(http.StatusUnauthorized)return}next.ServeHTTP(w,r)})}
Most OIDC providers expose metadata at /.well-known/openid-configuration. Proxy this to the OAuth2 ASM endpoint:
1
2
3
4
5
mux.HandleFunc("/.well-known/oauth-authorization-server",func(whttp.ResponseWriter,r*http.Request){metadata:=GetMetadata()// Fetch from OIDC providerw.Header().Set("Content-Type","application/json")w.Write(metadata)})
6. Dynamic Client Registration
Use Dex’s gRPC API to create OAuth2 clients on demand:
Client Type Confusion: Visual Studio Code drops client secrets, requiring public clients. The MCP Inspector needs private clients. Test with both types.
Client Persistence: DCR clients stored in memory don’t survive restarts. Use persistent storage in production.
CORS Headers: Web clients require CORS support for all OAuth2 endpoints, not just the main API.
Next Steps
You now have a working OAuth2 gateway for MCP servers. The complete implementation is available at hyprmcp/mcp-gateway with additional features like configuration management and production-ready error handling.
Test your implementation with the MCP Who Am I server to verify JWT parsing and user information extraction.