Skip to content

Authentification ​

Les routes sont relatives à <PUBLIC_BASE_URL> ; les corps de requête et de réponse sont en JSON sauf mention contraire. L’authentification, les portées, la pagination et le format des erreurs sont décrits dans les guides de l’API REST.

POST /api/v1/auth/login ​

Se connecter

Ouvre une session et pose le cookie de session httpOnly. Limité en débit par IP avant toute lecture en base (voir Retry-After). Un corps malformé rend le même code qu’un mot de passe faux : la route n’est pas un oracle.

Accès — Aucune authentification.

Corps de la requête (application/json)

ChampTypeRequis
emailstringoui
passwordstringoui
Schéma JSON
json
{
  "type": "object",
  "properties": {
    "email": { "type": "string" },
    "password": { "type": "string", "minLength": 1, "maxLength": 256 }
  },
  "required": [ "email", "password" ]
}

Réponses

200 — Le membre et l’expiration de la session.

ChampTypeRequis
memberobjectoui
expiresAtstring (date-time)oui
Schéma JSON
json
{
  "type": "object",
  "properties": {
    "member": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid",
          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
        },
        "email": { "type": "string" },
        "name": { "type": "string" },
        "role": { "type": "string", "enum": [ "member", "admin" ] },
        "status": { "type": "string", "enum": [ "active", "suspended" ] }
      },
      "required": [ "id", "email", "name", "role", "status" ],
      "additionalProperties": false
    },
    "expiresAt": {
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
    }
  },
  "required": [ "member", "expiresAt" ],
  "additionalProperties": false
}

400 — La requête ne respecte pas son schéma.

Codes d’erreur — auth.invalid_credentials, auth.too_many_attempts, auth.https_required. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.

Exemple de requête

json
{ "email": "alice@example.test", "password": "correct horse battery staple" }

Exemple de réponse (200)

json
{
  "member": {
    "id": "0192f1c2-0000-7000-8000-000000000001",
    "email": "alice@example.test",
    "name": "Alice",
    "role": "admin",
    "status": "active"
  },
  "expiresAt": "2026-10-11T09:00:00.000Z"
}

POST /api/v1/auth/logout ​

Se déconnecter

Révoque la session et efface le cookie. Idempotent : répond 200 même sans session.

Accès — Session de membre seulement : les clés d’API sont refusées (api_key.session_required).

Réponses

200 — Déconnecté.

ChampTypeRequis
status"ok"oui
Schéma JSON
json
{
  "type": "object",
  "properties": { "status": { "type": "string", "const": "ok" } },
  "required": [ "status" ],
  "additionalProperties": false
}

401 — Aucune session ni clé d’API valide (auth.unauthenticated).

403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).

429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.

GET /api/v1/auth/me ​

Qui suis-je

Le membre connecté, l’expiration de la session, les préférences publiques (langue, mode d’affichage, thème) et la date d’arrivée.

Accès — Session de membre ou clé d’API portant profile:read.

Réponses

200 — Le membre courant.

ChampTypeRequis
memberobjectoui
expiresAtstring (date-time)oui
settingsobjectoui
joinedAtstring (date-time)non
Schéma JSON
json
{
  "type": "object",
  "properties": {
    "member": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid",
          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
        },
        "email": { "type": "string" },
        "name": { "type": "string" },
        "role": { "type": "string", "enum": [ "member", "admin" ] },
        "status": { "type": "string", "enum": [ "active", "suspended" ] }
      },
      "required": [ "id", "email", "name", "role", "status" ],
      "additionalProperties": false
    },
    "expiresAt": {
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
    },
    "settings": {
      "default": {},
      "type": "object",
      "properties": {
        "locale": { "type": "string", "enum": [ "fr", "en" ] },
        "theme": { "type": "string", "enum": [ "light", "dark", "system" ] },
        "themeName": { "type": "string", "enum": [ "classic", "meridian", "atelier" ] }
      },
      "additionalProperties": false
    },
    "joinedAt": {
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
    }
  },
  "required": [ "member", "expiresAt", "settings" ],
  "additionalProperties": false
}

401 — Aucune session ni clé d’API valide (auth.unauthenticated).

403 — Refusé : rôle insuffisant (auth.forbidden), portée manquante (api_key.scope_missing, details.required la nomme) ou route fermée aux clés (api_key.session_required).

429 — La clé d’API dépasse son débit (api_key.rate_limited) ; Retry-After dit quand réessayer.

POST /api/v1/auth/accept-invitation ​

Accepter une invitation

Crée le membre et consomme l’invitation, atomiquement. N’ouvre pas de session : le nouveau membre se connecte avec le mot de passe qu’il vient de choisir. Jeton inconnu, périmé ou consommé rendent le même code. Limité en débit comme la connexion.

Accès — Aucune authentification.

Corps de la requête (application/json)

ChampTypeRequis
tokenstringoui
namestringoui
passwordstringoui
Schéma JSON
json
{
  "type": "object",
  "properties": {
    "token": { "type": "string", "minLength": 1, "maxLength": 200 },
    "name": { "type": "string", "minLength": 1, "maxLength": 200 },
    "password": { "type": "string", "minLength": 12, "maxLength": 256 }
  },
  "required": [ "token", "name", "password" ]
}

Réponses

201 — Le membre, créé.

ChampTypeRequis
memberobjectoui
Schéma JSON
json
{
  "type": "object",
  "properties": {
    "member": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid",
          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
        },
        "email": { "type": "string" },
        "name": { "type": "string" },
        "role": { "type": "string", "enum": [ "member", "admin" ] },
        "status": { "type": "string", "enum": [ "active", "suspended" ] }
      },
      "required": [ "id", "email", "name", "role", "status" ],
      "additionalProperties": false
    }
  },
  "required": [ "member" ],
  "additionalProperties": false
}

400 — La requête ne respecte pas son schéma.

Codes d’erreur — governance.invalid_invitation, governance.member_exists, auth.too_many_attempts. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.

GET /api/v1/invitations/{token} ​

Aperçu d’une invitation

Y a-t-il un formulaire à afficher ? Rend l’adresse masquée, le nom de l’organisation et l’expiration. Contrairement à l’acceptation elle distingue ses refus : 404 inconnu, 410 périmé, 409 déjà accepté. Partage la limite de débit de l’acceptation.

Accès — Aucune authentification.

Paramètres

NomOùTypeRequis
tokencheminstringoui

Réponses

200 — L’invitation, utilisable.

ChampTypeRequis
emailstringoui
organizationNamestringoui
expiresAtstring (date-time)oui
Schéma JSON
json
{
  "type": "object",
  "properties": {
    "email": { "type": "string" },
    "organizationName": { "type": "string" },
    "expiresAt": {
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
    }
  },
  "required": [ "email", "organizationName", "expiresAt" ],
  "additionalProperties": false
}

Codes d’erreur — governance.invitation_invalid, governance.invitation_expired, governance.invitation_already_accepted, auth.too_many_attempts. Les codes communs (request.bad_request, auth.unauthenticated, api_key.scope_missing, api_key.rate_limited…) s’appliquent à toutes les routes ; voir Erreurs.