Aller au contenu

Autorisation (OAuth 2.1)

VibeSell gère son propre serveur d’autorisation OAuth 2.1, conçu pour les clients MCP : clients publics avec PKCE, inscription dynamique des clients, et une page d’accord où le titulaire du compte se connecte. Pas besoin d’identifiant ni de secret client : un client conforme découvre et enregistre tout lui-même.

  1. Défi. Un POST /v1/mcp non authentifié répond 401 avec WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/v1/mcp", scope="mcp mcp:act".

  2. Découverte. Le client lit les métadonnées de la ressource protégée (ses authorization_servers), puis /.well-known/oauth-authorization-server.

  3. Inscription. Le client envoie ses métadonnées en POST à /v1/oauth/register et reçoit un client_id.

  4. Autorisation. Le client envoie le navigateur vers /v1/oauth/authorize avec response_type=code, un code_challenge PKCE (S256), son redirect_uri, un state et la resource. VibeSell redirige vers sa page d’accord, où l’utilisateur se connecte et clique sur Allow.

  5. Code. VibeSell redirige vers le redirect_uri avec code, state et iss.

  6. Jeton. Le client échange le code et son code_verifier sur /v1/oauth/token contre un jeton d’accès et un jeton de rafraîchissement.

GET /.well-known/oauth-authorization-server
{
"issuer": "https://api.vibesell.it",
"authorization_endpoint": "https://api.vibesell.it/v1/oauth/authorize",
"token_endpoint": "https://api.vibesell.it/v1/oauth/token",
"registration_endpoint": "https://api.vibesell.it/v1/oauth/register",
"revocation_endpoint": "https://api.vibesell.it/v1/oauth/revoke",
"response_types_supported": [
"code"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"code_challenge_methods_supported": [
"S256"
],
"token_endpoint_auth_methods_supported": [
"none"
],
"revocation_endpoint_auth_methods_supported": [
"none"
],
"scopes_supported": [
"mcp",
"mcp:act"
],
"authorization_response_iss_parameter_supported": true
}
GET /.well-known/oauth-protected-resource/v1/mcp
{
"resource": "https://api.vibesell.it/v1/mcp",
"authorization_servers": [
"https://api.vibesell.it"
],
"scopes_supported": [
"mcp",
"mcp:act"
],
"bearer_methods_supported": [
"header"
],
"resource_name": "VibeSell"
}

POST /v1/oauth/register accepte des métadonnées client en JSON (RFC 7591) :

  • redirect_uris — de 1 à 10 adresses, chacune soit une URL https://, soit une URL http:// de loopback sur localhost, 127.0.0.1 ou [::1], sans fragment.
  • client_name — affiché sur la page d’accord (200 caractères maximum). À défaut, c’est l’hôte de la première URI de redirection qui s’affiche.

Les clients sont publics : token_endpoint_auth_method vaut none, et aucun secret n’est émis.

Paramètre Règle
client_id Un client inscrit. Un client inconnu est refusé sans redirection.
redirect_uri Une URI que le client a enregistrée. Une URI inconnue est refusée sans redirection.
response_type code uniquement.
code_challenge / code_challenge_method PKCE est obligatoire, S256 uniquement.
state Renvoyé tel quel ; 2 000 caractères maximum.
resource Facultatif ; s’il est fourni, il doit valoir https://api.vibesell.it/v1/mcp (une barre oblique finale est tolérée).
scope Voir ci-dessous.

La demande d’accord est valable 10 minutes ; le code d’autorisation, 2 minutes. La redirection de retour porte iss=https://api.vibesell.it (RFC 9207). Si l’utilisateur clique sur Deny, le client reçoit error=access_denied.

Périmètre Accorde
mcp La lecture. Toujours accordé.
mcp:act L’action dans le workspace : enregistrer le travail, préparer les cartes d’approbation.
  • Une requête qui ne nomme aucun de ces périmètres obtient les deux.
  • Une requête qui nomme mcp:act obtient mcp mcp:act ; une requête qui ne nomme que mcp obtient une connexion en lecture seule.
  • Les autres périmètres (offline_access…) sont ignorés : ils n’ouvrent ni ne bloquent rien.

La page d’accord liste ce que permettent les périmètres accordés avant que l’utilisateur ne dise oui.

Durée de vie
Jeton d’accès 60 minutes (expires_in: 3600)
Jeton de rafraîchissement 30 jours

Les jetons sont des chaînes opaques, que VibeSell ne stocke que sous forme de hash. Leur audience est la ressource MCP.

Rotation des jetons de rafraîchissement. Chaque appel grant_type=refresh_token révoque le jeton de rafraîchissement qu’il utilise et renvoie une nouvelle paire. Présenter un jeton de rafraîchissement déjà remplacé est traité comme un vol et révoque toute la connexion — sauf dans les 60 secondes qui suivent sa rotation, où l’appel échoue simplement avec invalid_grant (des clients comme Claude peuvent rafraîchir deux fois à la fois).

POST /v1/oauth/revoke (token encodé en formulaire, RFC 7009) révoque un jeton et répond 200. Les utilisateurs révoquent une connexion entière depuis Settings → Connected apps dans VibeSell.

Les points d’entrée OAuth répondent au format RFC 6749 / 7591 :

{ "error": "invalid_grant", "error_description": "the refresh_token was already used" }
error Quand
invalid_request Un paramètre absent ou mal formé — PKCE manquant, state trop long, redirect_uri non enregistré.
invalid_client client_id inconnu (HTTP 401 sur le point d’entrée du jeton, ce qui pousse les clients à se réinscrire).
invalid_grant Code ou jeton de rafraîchissement expiré, déjà utilisé ou inconnu ; vérificateur PKCE qui ne correspond pas.
unsupported_grant_type Un type d’autorisation autre que authorization_code ou refresh_token.
unsupported_response_type Un response_type autre que code.
invalid_target Une resource autre que l’URL du MCP.
invalid_redirect_uri Une inscription sans URI de redirection, avec trop d’URI, ou avec une URI ni https:// ni loopback.
access_denied L’utilisateur a cliqué sur Deny.