Découverte OAuth 2.1
STOA implémente les standards de découverte OAuth 2.1 pour que les agents AI et les clients OAuth puissent découvrir automatiquement les endpoints d'authentification et obtenir des tokens — sans coder en dur les URLs Keycloak.
Pourquoi la Découverte est Importante
Sans découverte, chaque client MCP devrait connaître :
- L'URL Keycloak
- Le nom du realm
- Le chemin de l'endpoint token
- Les types de grants supportés
Avec la découverte, le client n'a besoin que de l'URL du gateway (mcp.<YOUR_DOMAIN>) et peut découvrir tout le reste automatiquement.
Métadonnées de Ressource Protégée (RFC 9728)
GET /.well-known/oauth-protected-resource
Indique aux clients OAuth que cette ressource est protégée et où s'authentifier.
curl "https://mcp.<YOUR_DOMAIN>/.well-known/oauth-protected-resource"
Réponse :
{
"resource": "https://mcp.<YOUR_DOMAIN>",
"authorization_servers": [
"https://auth.<YOUR_DOMAIN>/realms/stoa"
],
"scopes_supported": [
"openid",
"profile",
"email",
"stoa:read",
"stoa:write",
"stoa:admin"
],
"bearer_methods_supported": ["header"]
}
| Champ | Description |
|---|---|
resource | L'identifiant de la ressource protégée (URL du gateway) |
authorization_servers | Liste des serveurs d'autorisation pouvant émettre des tokens |
scopes_supported | Scopes OAuth que la ressource comprend |
bearer_methods_supported | Comment présenter les tokens (header = en-tête Authorization) |
Métadonnées du Serveur d'Autorisation (RFC 8414)
GET /.well-known/oauth-authorization-server
Retourne les métadonnées du serveur d'autorisation. Les endpoints token et d'enregistrement pointent vers le gateway (pas directement vers Keycloak), permettant au gateway de proxifier ces requêtes.
curl "https://mcp.<YOUR_DOMAIN>/.well-known/oauth-authorization-server"
Réponse :
{
"issuer": "https://auth.<YOUR_DOMAIN>/realms/stoa",
"authorization_endpoint": "https://auth.<YOUR_DOMAIN>/realms/stoa/protocol/openid-connect/auth",
"token_endpoint": "https://mcp.<YOUR_DOMAIN>/oauth/token",
"registration_endpoint": "https://mcp.<YOUR_DOMAIN>/oauth/register",
"jwks_uri": "https://auth.<YOUR_DOMAIN>/realms/stoa/protocol/openid-connect/certs",
"scopes_supported": [
"openid", "profile", "email",
"stoa:read", "stoa:write", "stoa:admin"
],
"response_types_supported": ["code"],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token"
],
"token_endpoint_auth_methods_supported": [
"none",
"client_secret_basic",
"client_secret_post"
],
"code_challenge_methods_supported": ["S256"],
"subject_types_supported": ["public"]
}
Points clés :
token_endpointpointe vers le gateway (/oauth/token), pas directement vers Keycloakregistration_endpointpointe vers le gateway (/oauth/register) pour le DCRauthorization_endpointpointe vers Keycloak (page de connexion côté utilisateur)- PKCE S256 est requis pour les flux authorization code
Découverte OpenID Connect
GET /.well-known/openid-configuration
Proxifie le document de découverte OIDC de Keycloak, en remplaçant les endpoints token et d'enregistrement pour passer par le gateway.
curl "https://mcp.<YOUR_DOMAIN>/.well-known/openid-configuration"
La réponse est la découverte OIDC standard de Keycloak avec deux remplacements :
token_endpoint→https://mcp.<YOUR_DOMAIN>/oauth/tokenregistration_endpoint→https://mcp.<YOUR_DOMAIN>/oauth/register
| Statut | Signification |
|---|---|
200 OK | Document de découverte retourné |
502 Bad Gateway | Keycloak inaccessible |
503 Service Unavailable | Keycloak non configuré |
Proxy Token
POST /oauth/token
Proxy transparent vers l'endpoint token de Keycloak. Le gateway transmet le corps de la requête tel quel et retourne la réponse de Keycloak.
Grant Client Credentials :
curl -X POST "https://mcp.<YOUR_DOMAIN>/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=my-app" \
-d "client_secret=my-secret"
Grant Authorization Code (avec PKCE) :
curl -X POST "https://mcp.<YOUR_DOMAIN>/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "client_id=my-app" \
-d "code_verifier=PKCE_VERIFIER" \
-d "redirect_uri=https://myapp.example.com/callback"
Réponse :
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "refresh-token-xyz",
"scope": "openid profile email stoa:read"
}
| Statut | Signification |
|---|---|
200 OK | Token émis |
400 Bad Request | Grant ou paramètres invalides |
401 Unauthorized | Identifiants client invalides |
502 Bad Gateway | Keycloak inaccessible |
Enregistrement Dynamique de Clients (DCR)
POST /oauth/register
Proxy vers l'endpoint DCR de Keycloak. Après l'enregistrement, le gateway patche automatiquement le client pour qu'il soit public (sans client_secret) avec le support PKCE S256 — requis pour les agents AI comme Claude.ai.
curl -X POST "https://mcp.<YOUR_DOMAIN>/oauth/register" \
-H "Content-Type: application/json" \
-d '{
"client_name": "claude-mcp-connector",
"application_type": "web",
"grant_types": ["authorization_code"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"redirect_uris": ["https://claude.ai/oauth/callback"]
}'
Réponse (201 Created) :
{
"client_id": "new-client-abc123",
"client_name": "claude-mcp-connector",
"application_type": "web",
"grant_types": ["authorization_code"],
"response_types": ["code"],
"registration_access_token": "rat-xyz",
"registration_client_uri": "https://auth.<YOUR_DOMAIN>/..."
}
Patch PKCE Post-Enregistrement
Après un enregistrement réussi, le gateway :
- Obtient automatiquement un token admin de Keycloak
- Trouve le client nouvellement créé
- Le patche pour définir
publicClient: trueetpkce.code.challenge.method: S256
Cela garantit que les agents AI peuvent s'authentifier en utilisant le flux authorization code avec PKCE, sans avoir besoin d'un client secret.
| Statut | Signification |
|---|---|
201 Created | Client enregistré |
400 Bad Request | Paramètres d'enregistrement invalides |
403 Forbidden | DCR désactivé dans Keycloak |
502 Bad Gateway | Keycloak inaccessible |
Exemple d'Intégration d'Agent AI
Voici comment un agent AI (ex : Claude.ai) découvre et s'authentifie avec STOA :
- Découverte :
GET /.well-known/oauth-protected-resource→ trouve le serveur d'autorisation - Métadonnées :
GET /.well-known/oauth-authorization-server→ trouve l'endpoint token, les flux supportés - Enregistrement (première fois) :
POST /oauth/register→ obtient leclient_id - Autorisation : Redirige l'utilisateur vers la connexion Keycloak → obtient le code d'autorisation
- Token :
POST /oauth/tokenavec code + vérificateur PKCE → obtient le token d'accès - Appel des tools :
POST /mcp/tools/callavecAuthorization: Bearer <token>
Voir Aussi
- MCP Gateway API — Endpoints du protocole MCP
- Guide d'Authentification — Configuration Keycloak et OIDC
- Permissions RBAC — Rôles et scopes
- Configuration de Sécurité — Bonnes pratiques de sécurité