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
- L'application externe appelle
POST /api/auth/login. - Le serveur renvoie un cookie HTTP-only.
- 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 Requestsiusernameoupasswordsont absents.401 Unauthorizedsi les identifiants sont invalides.5xxou 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 Requestsiusername,emailoupasswordsont absents.400 Bad RequestsipasswordetconfirmPassworddifferent.409 Conflictsi 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 Unauthorizedsi 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,TimeouLes deux.
Erreurs frequentes :
400 Bad Requestsi la valeur depreferredFormatest invalide.400 Bad Requestsi une longueur maximale est depassee.401 Unauthorizedsans 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 :
friendsreceivedInvitationssentInvitations
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
queryest 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 Requestsiquerycontient moins de 2 caracteres.401 Unauthorizedsans 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 Requestsi on tente de s'inviter soi-meme.400 Bad Requestsi le joueur cible est introuvable.400 Bad Requestsi le joueur est deja ami.400 Bad Requestsi 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 Requestsi 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 Requestsi l'invitation est introuvable ou deja traitee.
DELETE /api/social/invitations/{invitationId}
Annule une invitation envoyee.
Reponse 204 No Content
Erreur frequente :
400 Bad Requestsi 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 Unauthorizedsi l'utilisateur n'est pas connecte.403 Forbiddensi l'utilisateur est connecte mais n'a pas le roleadmin.
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 Foundsi 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 :
usernameobligatoire, max 120 caracteres.emailfacultatif mais valide si fourni, max 255 caracteres.passwordobligatoire, minimum 8 caracteres.confirmPassworddoit correspondre apassword.firstName,lastName,displayName,club,city,favoriteCube: 120 caracteres max.bio: 1200 caracteres max.preferredFormat:Twice,TimeouLes deux.
Erreurs frequentes :
400 Bad Requestsur validation metier.409 Conflictsi 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
usernamen'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 Requestsur validation metier.404 Not Foundsi l'utilisateur est introuvable.409 Conflictsi 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 Foundsi 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 surusernameouemail.
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/sessionpour verifier rapidement l'etat de connexion et les roles. - Utiliser
GET /api/users/mepour recuperer le profil courant. - Utiliser
GET /api/social/searchsi l'objectif est de rechercher des joueurs connectes au site. - Utiliser
GET /api/admin/usersuniquement pour une application d'administration portant le roleadmin.