Files
chesscubing/doc/api-utilisateurs.md

15 KiB

API utilisateurs pour applications externes

Ce document decrit les endpoints exposes par ChessCubing pour authentifier un utilisateur, recuperer son profil, rechercher d'autres joueurs, gerer les relations sociales, et administrer les comptes.

Les exemples ci-dessous utilisent http://localhost:8080 comme URL locale. En production, remplacez cette base par l'URL de votre instance.

Vue d'ensemble

  • API HTTP REST en JSON.
  • Authentification par cookie de session, pas par bearer token applicatif.
  • Cookie principal : chesscubing.auth
  • Duree de vie du cookie : 30 jours, avec renouvellement glissant.
  • Les dates sont retournees en UTC, au format ISO 8601.
  • Les applications navigateur sur un autre domaine ne peuvent pas consommer cette API directement aujourd'hui : aucune politique CORS n'est configuree cote serveur. Pour une integration externe, privilegier un appel serveur a serveur, ou ajouter CORS dans l'application.

Authentification

Principe

  1. L'application externe appelle POST /api/auth/login.
  2. Le serveur renvoie un cookie HTTP-only.
  3. Les appels suivants doivent reutiliser ce cookie.

Exemple curl avec conservation du cookie :

curl -sS -c cookies.txt \
  -H "Content-Type: application/json" \
  -d '{"username":"kiki","password":"motdepasse"}' \
  http://localhost:8080/api/auth/login

Puis reutilisation du cookie :

curl -sS -b cookies.txt http://localhost:8080/api/users/me

POST /api/auth/login

Authentifie un utilisateur Keycloak, cree si besoin son profil site, puis ouvre une session cookie.

Requete :

{
  "username": "kiki",
  "password": "motdepasse"
}

Reponse 200 OK :

{
  "isAuthenticated": true,
  "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
  "username": "kiki",
  "name": "Christophe JEANNEROT",
  "email": "christophe@jeannerot.fr",
  "roles": ["player", "admin"]
}

Erreurs frequentes :

  • 400 Bad Request si username ou password sont absents.
  • 401 Unauthorized si les identifiants sont invalides.
  • 5xx ou autre code issu de Keycloak si l'authentification amont est indisponible.

POST /api/auth/register

Cree un compte Keycloak, attribue le role player, connecte l'utilisateur et initialise son profil site.

Requete :

{
  "username": "kiki",
  "email": "christophe@jeannerot.fr",
  "password": "motdepasse123",
  "confirmPassword": "motdepasse123",
  "firstName": "Christophe",
  "lastName": "JEANNEROT"
}

Reponse 200 OK :

{
  "isAuthenticated": true,
  "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
  "username": "kiki",
  "name": "Christophe JEANNEROT",
  "email": "christophe@jeannerot.fr",
  "roles": ["player"]
}

Erreurs frequentes :

  • 400 Bad Request si username, email ou password sont absents.
  • 400 Bad Request si password et confirmPassword different.
  • 409 Conflict si le nom d'utilisateur ou l'email existe deja.

GET /api/auth/session

Retourne l'etat de session courant. Cette route est publique.

Si l'utilisateur est connecte :

{
  "isAuthenticated": true,
  "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
  "username": "kiki",
  "name": "Christophe JEANNEROT",
  "email": "christophe@jeannerot.fr",
  "roles": ["player", "admin"]
}

Si l'utilisateur n'est pas connecte :

{
  "isAuthenticated": false,
  "subject": null,
  "username": null,
  "name": null,
  "email": null,
  "roles": []
}

POST /api/auth/logout

Ferme la session courante et vide le cookie d'authentification.

Reponse 200 OK :

{
  "isAuthenticated": false,
  "subject": null,
  "username": null,
  "name": null,
  "email": null,
  "roles": []
}

GET /api/auth/logout/browser

Equivalent navigateur de la deconnexion. Cette route supprime le cookie puis redirige vers /index.html.

Profil du compte courant

Ces routes permettent a une application connectee de recuperer et modifier le profil site de l'utilisateur courant.

GET /api/users/me

Necessite une session authentifiee.

Reponse 200 OK :

{
  "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
  "username": "kiki",
  "email": "christophe@jeannerot.fr",
  "displayName": "Christophe JEANNEROT",
  "club": "ChessCubing Arena",
  "city": "Vercel Villedieu le camp",
  "preferredFormat": "Les deux",
  "favoriteCube": "GAN 12",
  "bio": "Joueur et organisateur.",
  "createdUtc": "2026-04-14T18:04:55.0000000Z",
  "updatedUtc": "2026-04-14T18:05:12.0000000Z"
}

Comportement notable :

  • Si le profil site n'existe pas encore, il est cree automatiquement.
  • 401 Unauthorized si aucun cookie valide n'est fourni.

PUT /api/users/me

Met a jour uniquement le profil site de l'utilisateur courant.

Requete :

{
  "displayName": "Christophe JEANNEROT",
  "club": "ChessCubing Arena",
  "city": "Vercel Villedieu le camp",
  "preferredFormat": "Les deux",
  "favoriteCube": "GAN 12",
  "bio": "Joueur et organisateur."
}

Reponse 200 OK : meme structure que GET /api/users/me.

Contraintes de validation :

  • displayName, club, city, favoriteCube : 120 caracteres max.
  • bio : 1200 caracteres max.
  • preferredFormat : Twice, Time ou Les deux.

Erreurs frequentes :

  • 400 Bad Request si la valeur de preferredFormat est invalide.
  • 400 Bad Request si une longueur maximale est depassee.
  • 401 Unauthorized sans session.

Recherche de joueurs et relations sociales

Ces routes necessitent toutes une session authentifiee.

GET /api/social/overview

Retourne la vue sociale du compte courant :

  • friends
  • receivedInvitations
  • sentInvitations

Reponse 200 OK :

{
  "friends": [
    {
      "subject": "sub-ami-1",
      "username": "alex",
      "displayName": "Alex Martin",
      "email": "alex@example.com",
      "club": "Club A",
      "city": "Paris",
      "isOnline": true
    }
  ],
  "receivedInvitations": [
    {
      "invitationId": 12,
      "subject": "sub-ami-2",
      "username": "lea",
      "displayName": "Lea Durand",
      "email": "lea@example.com",
      "isOnline": false,
      "createdUtc": "2026-04-15T08:15:00.0000000Z"
    }
  ],
  "sentInvitations": [
    {
      "invitationId": 18,
      "subject": "sub-ami-3",
      "username": "nina",
      "displayName": "Nina Bernard",
      "email": "nina@example.com",
      "isOnline": true,
      "createdUtc": "2026-04-15T08:18:00.0000000Z"
    }
  ]
}

GET /api/social/search?query={texte}

Recherche des joueurs connus du site par nom d'utilisateur, nom affiche, club, ville ou email selon l'index applicatif.

Exemple :

curl -sS -b cookies.txt \
  "http://localhost:8080/api/social/search?query=chri"

Reponse 200 OK :

[
  {
    "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
    "username": "kiki",
    "displayName": "Christophe JEANNEROT",
    "email": "christophe@jeannerot.fr",
    "club": "ChessCubing Arena",
    "city": "Vercel Villedieu le camp",
    "isOnline": true,
    "isFriend": false,
    "hasSentInvitation": false,
    "hasReceivedInvitation": true
  }
]

Comportement notable :

  • Si query est vide ou blanche, la route renvoie [].
  • La recherche exige au moins 2 caracteres utiles.
  • Le resultat est limite a 12 utilisateurs.

Erreurs frequentes :

  • 400 Bad Request si query contient moins de 2 caracteres.
  • 401 Unauthorized sans session.

POST /api/social/invitations

Envoie une invitation d'ami.

Requete :

{
  "targetSubject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28"
}

Reponse 204 No Content

Erreurs frequentes :

  • 400 Bad Request si on tente de s'inviter soi-meme.
  • 400 Bad Request si le joueur cible est introuvable.
  • 400 Bad Request si le joueur est deja ami.
  • 400 Bad Request si une invitation entre les deux comptes existe deja.

POST /api/social/invitations/{invitationId}/accept

Accepte une invitation recue.

Reponse 204 No Content

Erreur frequente :

  • 400 Bad Request si l'invitation est introuvable ou deja traitee.

POST /api/social/invitations/{invitationId}/decline

Refuse une invitation recue.

Reponse 204 No Content

Erreur frequente :

  • 400 Bad Request si l'invitation est introuvable ou deja traitee.

DELETE /api/social/invitations/{invitationId}

Annule une invitation envoyee.

Reponse 204 No Content

Erreur frequente :

  • 400 Bad Request si l'invitation est introuvable ou deja retiree.

DELETE /api/social/friends/{friendSubject}

Supprime une relation d'amitie.

Reponse 204 No Content

Administration des utilisateurs

Ces routes sont reservees aux sessions portant le role admin.

Sans ce role :

  • 401 Unauthorized si l'utilisateur n'est pas connecte.
  • 403 Forbidden si l'utilisateur est connecte mais n'a pas le role admin.

GET /api/admin/users

Retourne toute la liste des utilisateurs connus, en fusionnant :

  • les comptes Keycloak
  • les profils site MySQL

La reponse est triee par activite recente, puis par nom d'utilisateur.

Reponse 200 OK :

[
  {
    "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
    "username": "kiki",
    "email": "christophe@jeannerot.fr",
    "identityDisplayName": "Christophe JEANNEROT",
    "siteDisplayName": "Christophe JEANNEROT",
    "isEnabled": true,
    "isEmailVerified": false,
    "hasSiteProfile": true,
    "club": "ChessCubing Arena",
    "city": "Vercel Villedieu le camp",
    "preferredFormat": "Les deux",
    "accountCreatedUtc": "2026-04-14T17:44:00.0000000Z",
    "siteProfileUpdatedUtc": "2026-04-14T18:05:00.0000000Z"
  }
]

GET /api/admin/users/{subject}

Retourne le detail complet d'un utilisateur.

Reponse 200 OK :

{
  "subject": "2f7d0f1d-3ef6-4b5f-aab5-4cf6b61c0a28",
  "username": "kiki",
  "email": "christophe@jeannerot.fr",
  "firstName": "Christophe",
  "lastName": "JEANNEROT",
  "identityDisplayName": "Christophe JEANNEROT",
  "isEnabled": true,
  "isEmailVerified": false,
  "accountCreatedUtc": "2026-04-14T17:44:00.0000000Z",
  "hasSiteProfile": true,
  "displayName": "Christophe JEANNEROT",
  "club": "ChessCubing Arena",
  "city": "Vercel Villedieu le camp",
  "preferredFormat": "Les deux",
  "favoriteCube": "GAN 12",
  "bio": "Joueur et organisateur.",
  "siteProfileCreatedUtc": "2026-04-14T18:04:00.0000000Z",
  "siteProfileUpdatedUtc": "2026-04-14T18:05:00.0000000Z"
}

Erreurs frequentes :

  • 404 Not Found si l'utilisateur n'existe pas dans Keycloak.

POST /api/admin/users

Cree un utilisateur, son mot de passe, puis son profil site.

Requete :

{
  "username": "nouveau",
  "email": "nouveau@example.com",
  "password": "motdepasse123",
  "confirmPassword": "motdepasse123",
  "firstName": "Nouveau",
  "lastName": "Joueur",
  "isEnabled": true,
  "isEmailVerified": false,
  "displayName": "Nouveau Joueur",
  "club": "Club A",
  "city": "Paris",
  "preferredFormat": "Time",
  "favoriteCube": "Moyu RS3M",
  "bio": "Nouveau profil"
}

Reponse 201 Created :

  • En-tete Location: /api/admin/users/{subject}
  • Corps : meme structure que GET /api/admin/users/{subject}

Contraintes de validation :

  • username obligatoire, max 120 caracteres.
  • email facultatif mais valide si fourni, max 255 caracteres.
  • password obligatoire, minimum 8 caracteres.
  • confirmPassword doit correspondre a password.
  • firstName, lastName, displayName, club, city, favoriteCube : 120 caracteres max.
  • bio : 1200 caracteres max.
  • preferredFormat : Twice, Time ou Les deux.

Erreurs frequentes :

  • 400 Bad Request sur validation metier.
  • 409 Conflict si le nom d'utilisateur ou l'email existe deja.

PUT /api/admin/users/{subject}

Met a jour le compte Keycloak et le profil site.

Important :

  • Le username n'est pas modifiable via cette route.

Requete :

{
  "email": "christophe@jeannerot.fr",
  "firstName": "Christophe",
  "lastName": "JEANNEROT",
  "isEnabled": true,
  "isEmailVerified": true,
  "displayName": "Christophe JEANNEROT",
  "club": "ChessCubing Arena",
  "city": "Vercel Villedieu le camp",
  "preferredFormat": "Les deux",
  "favoriteCube": "GAN 12",
  "bio": "Joueur et organisateur."
}

Reponse 200 OK : meme structure que GET /api/admin/users/{subject}.

Erreurs frequentes :

  • 400 Bad Request sur validation metier.
  • 404 Not Found si l'utilisateur est introuvable.
  • 409 Conflict si l'email est deja utilise par un autre compte.

DELETE /api/admin/users/{subject}

Supprime :

  • le compte Keycloak
  • le profil site
  • les relations sociales et invitations associees

Reponse 204 No Content

Erreur frequente :

  • 404 Not Found si l'utilisateur est introuvable.

Temps reel via SignalR

Le hub /hubs/social est protege par authentification et permet :

  • la presence en ligne
  • les invitations de partie entre amis
  • la synchronisation d'une partie entre plusieurs devices

Les principaux messages/calls utilises sont :

  • appel client -> serveur RequestPresenceSnapshot
  • appel client -> serveur SendPlayInvite(recipientSubject, recipientColor)
  • appel client -> serveur RespondToPlayInvite(inviteId, accept)
  • appel client -> serveur CancelPlayInvite(inviteId)
  • appel client -> serveur JoinPlaySession(sessionId)
  • appel client -> serveur LeavePlaySession(sessionId)
  • appel client -> serveur PublishMatchState(sessionId, matchJson, route)
  • evenement serveur -> client PresenceSnapshot
  • evenement serveur -> client PresenceChanged
  • evenement serveur -> client PlayInviteUpdated
  • evenement serveur -> client PlayInviteAccepted
  • evenement serveur -> client PlayInviteClosed
  • evenement serveur -> client CollaborativeMatchStateUpdated

Pour un integrateur qui veut seulement recuperer les informations utilisateur, les endpoints REST de ce document sont generalement suffisants. Le hub devient utile des qu'il faut suivre la presence, les invitations ou l'etat partage d'une partie en temps reel.

Codes de reponse a prevoir

  • 200 OK : lecture ou action aboutie avec corps JSON.
  • 201 Created : creation d'utilisateur admin.
  • 204 No Content : action aboutie sans corps.
  • 400 Bad Request : erreur de validation ou session incomplete.
  • 401 Unauthorized : pas de session valide.
  • 403 Forbidden : session valide mais role insuffisant.
  • 404 Not Found : ressource introuvable, principalement cote admin.
  • 409 Conflict : doublon sur username ou email.

Recommandations d'integration

  • Stocker et rejouer le cookie de session si l'application externe fonctionne en backend.
  • Eviter les appels directs depuis un frontend sur un autre domaine tant que CORS n'est pas configure.
  • Utiliser GET /api/auth/session pour verifier rapidement l'etat de connexion et les roles.
  • Utiliser GET /api/users/me pour recuperer le profil courant.
  • Utiliser GET /api/social/search si l'objectif est de rechercher des joueurs connectes au site.
  • Utiliser GET /api/admin/users uniquement pour une application d'administration portant le role admin.