使用Ory Hydra OAuth的印度商店MCP服务器
一个生产就绪的模型上下文协议(MCP)服务器,具有由Ory Hydra支持的外部OAuth 2.0身份验证。此实现将身份验证问题分开: 您的MCP服务器处理用户身份验证,而 Ory Hydra负责OAuth令牌管理.
📖 目录
______________________________________________________________________
🏗️ 架构概述
高级体系结构
┌──────────────────────────────────────────────────────────────────┐
│ MCP CLIENTS │
│ (ChatGPT, Claude, Desktop Apps) │
└───────────────────────────┬──────────────────────────────────────┘
│
│ HTTPS
▼
┌──────────────────────────────────────────────────────────────────┐
│ GATEWAY API (Kubernetes) │
│ Routes: │
│ • /.well-known/* → MCP Server (OAuth Discovery) │
│ • /oauth2/* → Ory Hydra (OAuth Endpoints) │
│ • /oauth/register → MCP Server (Client Registration) │
│ • /login, /consent → MCP Server (Auth Handlers) │
│ • /mcp → MCP Server (Protected API) │
└────────────────┬────────────────┬────────────────────────────────┘
│ │
│ │
┌───────────▼───────┐ ┌──▼─────────────────────────┐
│ MCP SERVER │ │ ORY HYDRA │
│ (Port 8080) │◄───┤ (OAuth Provider) │
│ │ │ Public: 4444 │
│ Responsibilities: │ │ Admin: 4445 │
│ • User Auth │ │ │
│ • Login UI │ │ Responsibilities: │
│ • Consent │ │ • OAuth Protocol │
│ • Client Reg │ │ • Token Issuance │
│ • MCP Protocol │ │ • Token Validation │
│ • Token Validate │ │ • Client Storage │
└──────┬────────────┘ └───────┬────────────────────┘
│ │
│ │
▼ ▼
┌────────────────────────────────────────┐
│ PostgreSQL Database │
│ • users (MCP Server) │
│ • hydra_* tables (Ory Hydra) │
│ - clients │
│ - access_tokens │
│ - refresh_tokens │
│ - authorization_codes │
└────────────────────────────────────────┘关键的原则
您的MCP服务器=身份验证提供程序\ ORY HYDRA=OAuth令牌管理器
- 您控制世界卫生组织可以登录(用户数据库)
- 您验证密码
- Ory信任您的身份验证决定
- Ory处理OAuth复杂性
______________________________________________________________________
🎯 我们实施了什么
1.用户认证系统(internal/users/)
文件: users.go
它做什么:
- 在PostgreSQL中存储用户
- 使用bcrypt对密码进行哈希处理(成本10)
- 对用户进行身份验证(电子邮件+密码验证)
- 管理用户CRUD操作
关键功能:
NewUserStore(databaseURL) → Connects to PostgreSQL, creates tables
AddUser(email, password, name) → Adds user with hashed password
Authenticate(email, password) → Verifies credentials
GetUser(email) → Retrieves user info
ListUsers() → Returns all users (no passwords)
DeleteUser(email) → Removes user安全:
- 密码从不以明文形式存储
- bcrypt防止彩虹表攻击
- 通过参数化查询进行SQL注入保护
______________________________________________________________________
2.OAuth集成层(internal/oauth/)
2a。Ory HTTP客户端(ory_client.go)
它做什么:与Ory Hydra API通信
关键功能:
IntrospectToken(token) → Validates access token with Ory
GetAuthorizationURL(state) → Builds OAuth authorize URL
ExchangeCodeForToken(code) → Exchanges auth code for tokens
RefreshToken(refreshToken) → Gets new access token
GetUserInfo(accessToken) → Fetches user details重要:使用内部Kubernetes URL进行服务器到服务器的调用:
- 外部:
https://domain.com/ory(用于浏览器重定向) - 内部:
http://ory-hydra-public.default.svc.cluster.local:4444(用于代币兑换) - 管理员:
http://ory-hydra-admin.default.svc.cluster.local:4445(反省)
2b。动态客户端注册(registration.go)
它做什么:实现RFC 7591-客户端自行注册
流动:
1. ChatGPT calls: POST /oauth/register
2. MCP Server validates request
3. MCP Server forwards to Ory Admin API: POST /admin/clients
4. Ory creates client in PostgreSQL
5. Returns client_id + client_secret to ChatGPT为什么需要:ChatGPT/Claude没有预先配置的凭据
2c。登录和同意处理程序(login_consent.go)
它做什么:处理Ory的登录和同意重定向
登录流程:
1. Ory redirects to: /login?login_challenge=xyz
2. Check if user has session cookie
├─> YES → Auto-approve
└─> NO → Show login form
3. User submits email + password
4. Call userStore.Authenticate(email, password)
5. If valid:
└─> Call Ory Admin API: PUT /admin/oauth2/auth/requests/login/accept
Body: {"subject": "user@example.com"}
6. Ory trusts us: "This user is legit"
7. Redirect to consent同意流程:
1. Ory redirects to: /consent?consent_challenge=abc
2. Get user info from subject
3. Auto-approve consent
4. Call Ory Admin API: PUT /admin/oauth2/auth/requests/consent/accept
Body: {
"grant_scope": ["openid", "email"],
"session": {"id_token": {"email": "...", "name": "..."}}
}
5. Ory issues authorization code
6. Redirect back to client with code会话管理:
- 24小时会话Cookie
- HttpOnly、安全、SameSite=Lax
- 随机64个字符的会话ID
- 内存存储(可以移动到Redis)
2d。OAuth处理程序(handlers.go)
它做什么:OAuth流的帮助函数(在当前架构中没有大量使用)
______________________________________________________________________
3.认证中间件(internal/middleware/auth.go)
它做什么:保护 /mcp 端点
流动:
1. Extract Bearer token from Authorization header
2. Call oryClient.IntrospectToken(token)
3. Ory Admin API: POST /admin/oauth2/introspect
4. Ory checks PostgreSQL: Is token valid?
5. If active=true → Allow request
6. If active=false → Return 401 Unauthorized施加到: /mcp 端点(每个MCP协议请求)
______________________________________________________________________
4.配置管理(internal/config/config.go)
它做什么:从环境变量加载配置
关键变量:
ORY_URL // External URL (browser redirects)
ORY_INTERNAL_URL // Internal URL (token exchange)
ORY_ADMIN_URL // Admin API (introspection)
DATABASE_URL // PostgreSQL connection string
PORT // Server port (8080)验证:如果缺少所需的变量,则会很快失败
______________________________________________________________________
5.主服务器(main.go)
它做什么:将所有东西连接在一起
路线:
// OAuth Discovery
GET /.well-known/oauth-authorization-server → OAuth discovery metadata
// OAuth Flows
POST /oauth/register → Dynamic client registration
GET /login → Login form (or auto-approve if session exists)
POST /login → Process login credentials
GET /consent → Consent screen (auto-approve)
GET /oauth/authorize → Redirect to /oauth2/auth (compatibility)
// MCP Protocol
POST /mcp → Protected MCP endpoint (requires Bearer token)
// Health
GET /health → Health check初始化顺序:
- 加载配置
- 初始化Ory客户端
- 连接到PostgreSQL(用户存储)
- 创建处理程序(注册、登录/同意、身份验证中间件)
- 注册路由
- 启动HTTP服务器
______________________________________________________________________
🔄 工作原理:完整的OAuth流程
第一阶段:客户发现
ChatGPT → GET /.well-known/oauth-authorization-server
MCP Server → Returns:
{
"authorization_endpoint": "https://domain.com/oauth2/auth",
"token_endpoint": "https://domain.com/oauth2/token",
"registration_endpoint": "https://domain.com/oauth/register",
...
}第二阶段:动态客户注册
ChatGPT → POST /oauth/register
{
"client_name": "ChatGPT",
"redirect_uris": ["https://chatgpt.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "openid offline_access email profile"
}
MCP Server → Ory Admin API: POST /admin/clients
Ory → Creates client in PostgreSQL
Ory → Returns client_id + client_secret
MCP Server → Returns to ChatGPT存储:客户端存储在PostgreSQL中 hydra_client 桌子
第3阶段:授权请求
ChatGPT → Browser opens:
https://domain.com/oauth2/auth?
client_id=abc123&
redirect_uri=https://chatgpt.com/callback&
response_type=code&
scope=openid+email&
state=xyz
Ory Hydra → Checks: Is user authenticated?
Ory → NO → Redirects to: /login?login_challenge=challenge_token第4阶段:用户身份验证(由您控制)
Browser → GET /login?login_challenge=challenge_token
MCP Server:
1. Check session cookie
├─> Exists & Valid → Skip to step 5
└─> No session → Continue
2. Show login form HTML
3. User enters:
Email: john@company.com
Password: mypassword123
4. POST /login (form submission)
5. userStore.Authenticate("john@company.com", "mypassword123")
├─> Query PostgreSQL: SELECT * FROM users WHERE email = ?
├─> User found?
│ ├─> NO → Return "Invalid credentials" ❌
│ └─> YES → Continue
│
└─> bcrypt.CompareHashAndPassword(stored_hash, entered_password)
├─> Match?
│ ├─> NO → Return "Invalid credentials" ❌
│ └─> YES → User authenticated ✅
6. Create session (24h cookie)
7. Tell Ory user is authenticated:
PUT /admin/oauth2/auth/requests/login/accept?login_challenge=challenge_token
Body: {
"subject": "john@company.com",
"remember": true,
"remember_for": 86400
}
8. Ory trusts us: "OK, this user is legit"
9. Ory responds: {"redirect_to": "/consent?consent_challenge=consent_token"}
10. Redirect browser to consent URL关键点:Ory从未见过密码。你验证了它。
第五阶段:同意
Browser → GET /consent?consent_challenge=consent_token
MCP Server:
1. Call Ory: GET /admin/oauth2/auth/requests/consent?consent_challenge=consent_token
2. Ory returns:
{
"subject": "john@company.com",
"requested_scope": ["openid", "email", "profile"],
"client": {"client_id": "abc123"}
}
3. Get user from database: userStore.GetUser("john@company.com")
4. Auto-approve consent:
PUT /admin/oauth2/auth/requests/consent/accept?consent_challenge=consent_token
Body: {
"grant_scope": ["openid", "email", "profile"],
"remember": true,
"remember_for": 86400,
"session": {
"id_token": {
"email": "john@company.com",
"name": "John Doe"
}
}
}
5. Ory issues authorization code
6. Ory responds: {"redirect_to": "https://chatgpt.com/callback?code=AUTH_CODE"}
7. Redirect browser back to ChatGPT第六阶段:代币交换
ChatGPT → POST /oauth2/token (directly to Ory)
Body:
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=https://chatgpt.com/callback&
client_id=abc123&
client_secret=secret123
Ory → Validates:
✓ Authorization code valid?
✓ Client credentials correct?
✓ Redirect URI matches?
Ory → Returns:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid email profile"
}存储:存储在PostgreSQL中的令牌 hydra_access 和 hydra_refresh 表格
第7阶段:API访问
ChatGPT → POST /mcp
Header: Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Body: {"jsonrpc": "2.0", "method": "tools/list", "id": 1}
MCP Server (middleware/auth.go):
1. Extract Bearer token
2. Call oryClient.IntrospectToken(token)
POST /admin/oauth2/introspect (Ory Admin API)
Body: {"token": "eyJhbGciOiJSUzI1NiIs..."}
3. Ory checks PostgreSQL:
✓ Token exists?
✓ Token not expired?
✓ Token not revoked?
4. Ory returns:
{
"active": true,
"sub": "john@company.com",
"scope": "openid email profile",
"exp": 1734567890
}
5. If active=true → Process MCP request
6. If active=false → Return 401 Unauthorized
MCP Server (main.go):
7. Process JSON-RPC request
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "list_indian_stores",
"description": "...",
"inputSchema": {...}
}
]
}
}______________________________________________________________________
📁 目录结构
indian-store-mcp-server/
├── main.go # Main server (routes, initialization)
├── internal/
│ ├── config/
│ │ └── config.go # Configuration loader
│ ├── users/
│ │ └── users.go # User management (PostgreSQL)
│ ├── oauth/
│ │ ├── ory_client.go # Ory HTTP client
│ │ ├── registration.go # Dynamic client registration
│ │ ├── login_consent.go # Login/consent handlers
│ │ └── handlers.go # OAuth helper functions
│ └── middleware/
│ └── auth.go # Token validation middleware
├── k8s/
│ ├── .gitignore # Git ignore rules for k8s
│ ├── configmap.yaml # ConfigMap and secrets for MCP server
│ ├── deployement.yaml # MCP server deployment and service
│ ├── gateway.yaml # Gateway API configuration
│ ├── README.md # Kubernetes deployment guide
│ └── hydra/
│ ├── README.md # Ory Hydra deployment guide
│ ├── postgres-sts.yaml # PostgreSQL StatefulSet for Hydra
│ └── ory-hydra-values.yaml # Helm values for Ory Hydra
├── Dockerfile
├── go.mod
├── go.sum
├── README.md # This file
├── INSTALLATION.md # Deployment guide
└── AUTHENTICATION.md # Security deep dive______________________________________________________________________
🔐 安全模型
身份验证层
- 用户认证 (您的MCP服务器)
- 电子邮件/密码验证 - bcrypt密码散列(成本10) - PostgreSQL用户存储 - 会话管理(24小时Cookie)
- OAuth令牌验证 (九头蛇)
- 访问令牌自检 - 令牌过期检查 - 令牌撤销支持 - 刷新令牌轮换
信任边界
┌─────────────────────────┐
│ Your MCP Server │
│ (Trusted) │
│ • Verifies passwords │
│ • Creates sessions │
│ • Tells Ory who's OK │
└───────────┬─────────────┘
│ Admin API (trusted)
▼
┌─────────────────────────┐
│ Ory Hydra │
│ (Trusts your auth) │
│ • Issues tokens │
│ • Validates tokens │
└─────────────────────────┘什么不能被忽视
- ❌ 没有kubectl/数据库访问权限,无法创建用户
- ❌ 没有正确的密码无法登录
- ❌ 无法伪造OAuth令牌
- ❌ 没有有效令牌无法访问MCP
- ❌ 无法使用过期的令牌
______________________________________________________________________
🚀 快速开始
看 安装.md 获取完整的部署指南。
太长,读不下去了:
# 1. Deploy PostgreSQL
kubectl apply -f k8s/hydra/postgres-sts.yaml
# 2. Deploy Ory Hydra
helm install ory-hydra ory/hydra -f k8s/hydra/ory-hydra-values.yaml
# 3. Deploy MCP Server
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/deployement.yaml
kubectl apply -f k8s/gateway.yaml
# 4. Create a user
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c \
"INSERT INTO users (email, password_hash, name)
VALUES ('admin@example.com', '', 'Admin');"______________________________________________________________________
👤 用户管理
用户管理直接通过PostgreSQL数据库处理。只有在数据库中创建的用户才能对系统进行身份验证。
创建用户
1.为密码生成bcrypt哈希:
python3 -c "import bcrypt; print(bcrypt.hashpw(b'your_password', bcrypt.gensalt(rounds=10)).decode())"2.将用户插入数据库:
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c \
"INSERT INTO users (email, password_hash, name) VALUES ('user@example.com', '\$2a\$10\$HASH_HERE', 'User Name');"3.验证用户是否已创建:
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c \
"SELECT email, name, created_at FROM users WHERE email = 'user@example.com';"管理用户
列出所有用户:
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c \
"SELECT email, name, created_at FROM users;"更新用户密码:
# Generate new hash first
python3 -c "import bcrypt; print(bcrypt.hashpw(b'new_password', bcrypt.gensalt(rounds=10)).decode())"
# Update in database
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c \
"UPDATE users SET password_hash = '\$2a\$10\$NEW_HASH' WHERE email = 'user@example.com';"删除用户:
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c \
"DELETE FROM users WHERE email = 'user@example.com';"安全须知
- 密码存储为bcrypt哈希值(成本10)-它们不能反转为明文
- 只有具有Kubernetes访问权限的管理员才能创建、更新或删除用户
- 用户必须存在于数据库中才能进行身份验证
- 不存在自我注册功能-所有用户管理都必须手动完成
______________________________________________________________________
🧪 测试
测试OAuth发现
curl https://your-domain.com/.well-known/oauth-authorization-server测试健康状况
curl https://your-domain.com/health使用ChatGPT进行测试
- 转到ChatGPT设置→ 集成
- 添加MCP服务器:
https://your-domain.com - 出现提示时登录
- 应显示“已连接”
______________________________________________________________________
🐛 故障排除
检查MCP服务器日志
kubectl logs -l app=mcp-service-indian-store --tail=100检查Ory Hydra日志
kubectl logs -l app.kubernetes.io/name=hydra --tail=100常见问题
401未经授权上/mcp:
- 检查令牌是否有效:令牌可能已过期
- 验证Ory管理员URL是否为内部URL:
http://ory-hydra-admin.default.svc.cluster.local:4445
登录页面未显示:
- 检查网关路由:
kubectl get httproute - 验证MCP服务器是否正在运行:
kubectl get pods
pod重启后用户坚持:
- ✅ 用户在PostgreSQL中(持久)
- ✅ 检查数据库:
kubectl exec -it deployment/postgres -- psql -U ory_hydra -d ory_hydra -c "SELECT * FROM users;"
______________________________________________________________________
📚 其他文件
______________________________________________________________________
🤝 贡献
这是一个参考实现。请随时根据您的需求进行调整:
- 用Redis替换内存会话
- 添加2FA/MFA支持
- 实现用户注册UI(如果需要)
- 添加RBAC/权限
- 与LDAP/AD集成
______________________________________________________________________
📄 许可证
MIT许可证
______________________________________________________________________
🔑 关键要点
- 您的MCP服务器拥有用户身份验证 -您可以控制谁可以登录
- Ory Hydra拥有OAuth复杂性 -令牌管理、刷新、撤销
- 通过管理员API信任 -Ory信任您的身份验证决定
- 关注点分离 -与令牌管理分离的身份验证逻辑
- 生产准备就绪 -外部OAuth提供者,持久存储,可扩展
美丽:您无需构建OAuth服务器即可获得企业OAuth!
