API Reference

AXIUM Identity API

Service central d'identité pour les applications AXIUM. Il gère l'authentification via OAuth2 et Keycloak, ainsi que le chargement des rôles et permissions de chaque utilisateur. Cette page vous montre comment vous connecter, rafraîchir un token, et gérer chaque cas de réponse possible.

Présentation

AXIUM Identity valide votre application (client_id / client_secret), authentifie l'utilisateur via Keycloak, charge ses rôles et permissions, puis vous retourne un access_token et un refresh_token.

Démarrage rapide

Nouveau sur cette API ? Voici les 3 étapes à connaître avant de coder.

1

Obtenir un token

Envoyez vos identifiants à POST /api/oauth/token. Vous recevez un access_token valable 300 secondes.

2

Appeler l'API

Ajoutez le header Authorization: Bearer {access_token} à chaque requête protégée.

3

Rafraîchir avant expiration

Utilisez POST /api/oauth/refresh avec le refresh_token pour obtenir un nouveau couple de tokens sans redemander le mot de passe.

Flux d'authentification

  • L'application cliente fournit son client_id et client_secret.
  • AXIUM Identity valide l'application.
  • L'utilisateur est authentifié via Keycloak.
  • Les rôles et permissions sont chargés.
  • Un access_token et un refresh_token sont retournés.

Connexion utilisateur

Authentifie un utilisateur et retourne ses tokens, rôles et permissions.

POST /api/oauth/token

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant public de l'application cliente.
client_secretstringOuiSecret privé fourni lors de la création de l'application.
usernamestringOuiEmail ou identifiant utilisateur.
passwordstringOuiMot de passe utilisateur.

Exemple de requête

Requête
POST /api/oauth/token
Content-Type: application/json

{
    "client_id": "axium-stock",
    "client_secret": "xxxxxxxx",
    "username": "byao@sifogroup.com",
    "password": "123456"
}

Réponses possibles

Cliquez sur un code pour voir le format exact retourné par l'API.

200 OK
{
    "success": true,
    "token_type": "Bearer",
    "access_token": "eyJhbGciOiJSU.....",
    "refresh_token": "eyJhbGciOiJI.....",
    "expires_in": 300,
    "user": {
        "id": 1,
        "email": "byao@sifogroup.com",
        "first_name": "Benjamin",
        "last_name": "YAO",
        "active": true
    },
    "roles": [
        "ROLE_USER",
        "ROLE_ADMIN",
        "ROLE_COMMERCIAL"
    ],
    "permissions": [
        "CREATE_USER",
        "CREATE_CARD",
        "CREATE_VOYAGE",
        "VIEW_USER_DASHBOAD"
    ]
}
Note : utilisez permissions si vous avez juste besoin de vérifier des droits dans votre code (ex. if permissions.includes('CREATE_CARD')).
401 Unauthorized · INVALID_CLIENT
{
    "success": false,
    "error": {
        "code": "INVALID_CLIENT",
        "message": "Client inconnu.",
        "details": []
    }
}
Le client_id envoyé n'existe pas côté AXIUM Identity. Vérifiez qu'il correspond bien à celui de votre application.
401 Unauthorized · INVALID_CLIENT_SECRET
{
    "success": false,
    "error": {
        "code": "INVALID_CLIENT_SECRET",
        "message": "Client secret invalide.",
        "details": []
    }
}
Le client_id est correct mais le client_secret ne correspond pas.
401 Unauthorized · AUTHENTICATION_FAILED
{
    "success": false,
    "error": {
        "code": "AUTHENTICATION_FAILED",
        "message": "Identifiants incorrects.",
        "details": []
    }
}
Le username existe mais le password est incorrect.
401 Unauthorized · AUTHENTICATION_FAILED
{
    "success": false,
    "error": {
        "code": "AUTHENTICATION_FAILED",
        "message": "Utilisateur invalide.",
        "details": []
    }
}
Même code que ci-dessus (AUTHENTICATION_FAILED) mais message différent : ici le username ne correspond à aucun compte. Si vous distinguez les deux cas côté front, testez sur le champ message, pas seulement sur code.
403 Forbidden · APP_ACCESS_DENIED
{
    "success": false,
    "error": {
        "code": "APP_ACCESS_DENIED",
        "message": "Accès refusé. Votre compte ne dispose pas des autorisations requises pour utiliser cette application.",
        "details": []
    }
}
Les identifiants sont corrects, mais ce compte n'a pas le droit d'accéder à cette application cliente précise.

Rafraîchir un token

Génère un nouveau access_token à partir du refresh_token, sans redemander les identifiants.

POST /api/oauth/refresh

Paramètres

ParamètreTypeObligatoireDescription
refresh_tokenstringOuiToken de rafraîchissement obtenu lors de la connexion.

Exemple de requête

Requête
POST /api/oauth/refresh
Content-Type: application/json

{
    "refresh_token": "eyJhbGciOi..."
}

Réponse — 200 OK

200 OK
{
    "success": true,
    "token_type": "Bearer",
    "access_token": "eyJhbGciOi...",
    "refresh_token": "eyJhbGciOi...",
    "expires_in": 300
}
En cas d'échec, ce endpoint retourne le même format d'erreur commun décrit dans Format des erreurs (le plus fréquent étant un refresh_token expiré ou invalide).

Déconnexion

Révoque le refresh token et termine la session utilisateur côté Keycloak.

POST /api/oauth/logout

Paramètres

ParamètreTypeObligatoireDescription
refresh_tokenstringOuiRefresh token à invalider.

Exemple de requête

Requête
POST /api/oauth/logout
Content-Type: application/json

{
    "refresh_token": "eyJhbGciOi..."
}

Réponse — 200 OK

200 OK
{
    "success": true,
    "message": "Déconnexion réussie."
}

Utiliser le token

Toutes les API protégées nécessitent l'ajout du header HTTP suivant à chaque requête :

Header
Authorization: Bearer {access_token}

Créer un utilisateur

Crée un nouvel utilisateur et l'associe à l'application cliente appelante. Si un utilisateur possédant déjà cet email existe, il est mis à jour et l'application cliente lui est simplement ajoutée (aucune duplication de compte).

POST /api/user/create

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant de l'application cliente qui sera associée à l'utilisateur.
emailstringNonEmail de l'utilisateur. Il peut être absent si le compte est identifié autrement.
firstNamestringOuiPrénom de l'utilisateur.
lastNamestringOuiNom de l'utilisateur.
phonestringNonNuméro de téléphone au format international (ex: +2250709502322).
passwordstringOuiMot de passe de l'utilisateur.

Exemple de requête

Requête
POST /api/user/create
Content-Type: application/json

{
    "client_id": "op0a1a84-f8a6-461a-graz1-fd32fdcbf2cb",
    "email": "byao@sifogroup.com",
    "firstName": "Benjamin",
    "lastName": "YAO",
    "phone": "+2250709502322",
    "password": "123456"
}

Réponses possibles

Cliquez sur un code pour voir le format exact retourné par l'API.

200 OK
{
    "success": true,
    "message": "Utilisateur créé avec succès.",
    "client": "Axium Stock",
    "user": {
        "id": 14,
        "email": "byao@sifogroup.com"
    }
}
Note : ce cas se produit quand l'email fourni n'existe encore dans aucun compte AXIUM Identity. Un nouvel utilisateur est créé à la fois côté Keycloak et côté base AXIUM Identity, puis associé à l'application client_id fournie.
200 OK
{
    "success": true,
    "message": "Utilisateur modifié avec succès.",
    "client": "Axium Stock",
    "user": {
        "id": 7,
        "email": "byao@sifogroup.com"
    }
}
Ce cas se produit quand un compte avec cet email (ou ce keycloak_id) existe déjà. Le compte n'est pas dupliqué : l'application cliente client_id est simplement ajoutée à la liste des applications de l'utilisateur existant, et ses informations (nom, téléphone, etc.) sont mises à jour avec celles envoyées.
403 Forbidden
{
    "success": false,
    "message": "Client application invalide."
}
Le client_id envoyé n'existe pas côté AXIUM Identity.

Importer des employés depuis Excel

Importe un fichier Excel d'employés et crée ou met à jour chaque compte utilisateur associé à l'application cliente. Le fichier doit respecter le modèle officiel avec les colonnes matricule, nom, prenoms, date_entree, date_embauche et nom_utilisateur.

POST /api/user/create/by-import
Ce endpoint attend une requête multipart/form-data car il reçoit un fichier Excel.

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant public de l'application cliente concernée.
employeeFilefileOuiFichier Excel (.xlsx ou .xls) contenant la liste des employés à importer.

Structure du fichier Excel attendu

ColonneExempleDescription
matriculeEMP-001Matricule interne de l'employé.
nomYAONom de famille.
prenomsBenjaminPrénoms.
date_entree01/09/2026Date d'entrée.
date_embauche01/09/2026Date d'embauche.
nom_utilisateurbyaoIdentifiant utilisateur à créer ou utiliser.

Exemple de requête

Requête (multipart/form-data)
POST /api/user/create/by-import
Content-Type: multipart/form-data

client_id: AXIUM_RH
employeeFile: employes.xlsx

Réponses possibles

Cliquez sur un code pour voir le format exact retourné par l'API.

200 OK
{
    "success": true,
    "message": "Import des employés terminé avec succès.",
    "client": "AXIUM RH",
    "created": 2,
    "skipped": 0,
    "total": 2,
    "data": [
        {
            "action": "EDIT"
            "uuid": "01a0240d-8261-7699-82db-ebe2a927fce6",
            "username": "byao",
            "email": "byao@sifogroup.com",
            "firstName": "KOUAKOU BENJAMIN",
            "lastName": "YAO",
            "fullName": "YAO BENJAMIN",
            "phone": 0709502322,
            "active": true,
            "avatar": "https://127.0.0.1:8080/uploads/avatars/019f8ea8-4ad9-7291-ad2f-8a48c23be5f7.jpg",
            "signature": "https://127.0.0.1:8080/uploads/signatures/kouakou-benjamin-yao-signature-6a87401371222.png",
            "stamp": "https://127.0.0.1:8080/uploads/stamps/kouakou-benjamin-yao-stamp-6a87400591e70.png",
            "companyName": OPTIMUM SOLUTIONS,
            "matricule": "EMP-001",
            "dateEntree": "01/09/2026",
            "dateEmbauche": "01/09/2026"
        },
        {
           "action": "CREATE"
           "uuid": "01a0ac27-6d4a-7731-8612-e40c0dcc5325",
            "username": "akone",
            "email": null,
            "firstName": "ADJOUA",
            "lastName": "KONE",
            "fullName": "KONE ADJOUA",
            "phone": null,
            "active": true,
            "avatar": null,
            "signature": null,
            "stamp": null,
            "companyName": null,
            "matricule": "EMP-002",
            "dateEntree": "02/09/2026",
            "dateEmbauche": "02/09/2026"
        }
    ]
}
Note : created compte les lignes réellement traitées, skipped les lignes ignorées (ex. prénom ou nom vide), et data contient le détail de chaque création ou mise à jour. Le champ action vaut CREATE ou EDIT selon le cas.
400 Bad Request
{
    "success": false,
    "message": "Payload JSON invalide."
}
La requête est incomplète ; le fichier est absent, invalide ou la donnée envoyée ne correspond pas au format attendu.
403 Forbidden
{
    "success": false,
    "message": "Payload JSON invalide."
}
Le client_id envoyé n'existe pas côté AXIUM Identity.
422 Unprocessable Entity
{
    "success": false,
    "message": "Payload JSON invalide."
}
Le fichier n'est pas un Excel lisible, est vide, ou n'a pas les colonnes attendues : nom, prenoms et nom_utilisateur.

Modifier un utilisateur

Met à jour un utilisateur existant identifié par son uuid et l'associe à l'application cliente appelante. Cette route cible un compte précis pour éviter toute ambiguïté lors des mises à jour.

POST /api/user/update

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant de l'application cliente qui est utilisée pour la mise à jour.
uuidstringOuiUUID unique de l'utilisateur à modifier. Il sert de clé de ciblage.
emailstringNonNouvelle adresse email de l'utilisateur.
firstNamestringNonPrénom de l'utilisateur. Peut être omis lors d'une modification.
lastNamestringNonNom de l'utilisateur. Peut être omis lors d'une modification.
phonestringNonNouveau numéro de téléphone.

Exemple de requête

Requête
POST /api/user/update
Content-Type: application/json

{
    "client_id": "op0a1a84-f8a6-461a-graz1-fd32fdcbf2cb",
    "firstName": "KOUAKOU BENJAMIN",
    "lastName": "YAO"
}

Réponses possibles

Cliquez sur un code pour voir le format exact retourné par l'API.

200 OK
{
    "success": true,
    "message": "Utilisateur créé avec succès.",
    "client": "AXIUM TRANSPORT",
    "user": {
        "uuid": "01a0629f-e89b-7a6f-be77-16245efce7ae",
        "email": null,
        "username": "byao",
        "firstName": "KOUAKOU BENJAMIN",
        "lastName": "YAO",
        "fullName": "YAO KOUAKOU BENJAMIN",
        "phone": null,
        "active": true,
        "avatar": null,
        "signature": null,
        "stamp": null,
        "companyName": null,
        "roles": []
    }
}
Note : la modification cible un utilisateur précis grâce à son uuid. Cela évite de modifier n'importe quel compte lorsqu'il y a plusieurs profils avec des données proches.
400 Bad Request
{
    "success": false,
    "message": "Le uuid est obligatoire pour modifier un utilisateur."
}
Le champ uuid est absent ou vide. La route refuse d'aller plus loin pour éviter une modification non ciblée.
403 Forbidden
{
    "success": false,
    "message": "Client application invalide."
}
Le client_id fourni n'existe pas côté AXIUM Identity.
404 Not Found
{
    "success": false,
    "message": "Utilisateur introuvable pour ce uuid."
}
Aucun utilisateur ne correspond à ce uuid.

Réinitialiser le mot de passe

Remplace le mot de passe d'un utilisateur existant ciblé par son username.

POST /api/user/reset-password

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant public de l'application cliente.
usernamestringOuiUsername AXIUM IDENTITY de l'utilisateur à modifier.
passwordstringOuiNouveau mot de passe à appliquer.

Exemple de requête

Requête
POST /api/user/reset-password
Content-Type: application/json

{
    "client_id": "axium-stock",
    "username": "byao",
    "password": "NouveauMotDePasse123!"
}

Réponses possibles

Cliquez sur un code pour voir le format exact retourné par l'API.

200 OK
{
    "success": true,
    "message": "Mot de passe réinitialisé avec succès."
}
403 Forbidden
{
    "success": false,
    "message": "Client application invalide."
}
Le client_id envoyé n'existe pas côté AXIUM Identity.
404 Not Found
{
    "success": false,
    "message": "Utilisateur introuvable."
}
Aucun utilisateur ne correspond au username fourni.
422 Unprocessable Entity
{
    "success": false,
    "message": "Le nouveau mot de passe est invalide."
}
Le service Keycloak a refusé le nouveau mot de passe. Respectez les règles de sécurité configurées pour votre environnement.

Lister les utilisateurs par rôle ou permission

Retourne la liste des comptes qui correspondent à un rôle donné, ou à une permission donnée. Vous pouvez passer role ou permission, ou les deux si vous souhaitez filtrer plus finement.

GET /api/user/list

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant public de l'application cliente.
rolestringNonFiltre sur un rôle tel que ROLE_USER.
permissionstringNonFiltre sur une permission telle que CREATE_USER.

Exemples de requêtes

Rôle
GET /api/user/list?client_id=axium-stock&role=ROLE_USER
Permission
GET /api/user/list?client_id=axium-stock&permission=CREATE_USER

Réponses possibles

200 OK
{
    "success": true,
    "client": "Axium Stock",
    "count": 2,
    "users": [
        {
            "id": 12,
            "uuid": "01a0629f-e89b-7a6f-be77-16245efce7ae",
            "email": "byao@sifogroup.com",
            "firstName": "Benjamin",
            "lastName": "YAO",
            "fullName": "YAO Benjamin",
            "roles": ["ROLE_USER"]
        },
        {
            "id": 27,
            "uuid": "5fcb1dc4-5581-4b52-a1b7-2d14deec5c52",
            "email": "ctraore@sifogroup.com",
            "firstName": "Cyrille",
            "lastName": "TRAORE",
            "fullName": "TRAORE Cyrille",
            "roles": ["ROLE_USER"]
        }
    ]
}
Note : le filtre est basé sur les rôles et permissions réellement associés à l'utilisateur. Une permission est récupérée via le rôle qui y donne accès ; c'est ce qui permet de retrouver tous les comptes concernés par un droit comme CREATE_USER.
400 Bad Request
{
    "success": false,
    "message": "Au moins un paramètre est requis : role ou permission."
}
Le paramètre role ou permission est absent. La route refuse l'appel pour éviter une liste non filtrée.
403 Forbidden
{
    "success": false,
    "message": "Client application invalide."
}
Le client_id ne correspond à aucune application autorisée.

Uploader un avatar

Permet à une application cliente de mettre à jour la photo de profil d'un utilisateur. Le fichier est stocké et traité entièrement côté AXIUM Identity — l'application cliente ne fait que transmettre le fichier reçu depuis son formulaire.

POST /api/user/avatar/upload
Ce endpoint attend une requête multipart/form-data (et non du JSON), car un fichier est envoyé.

Paramètres

ParamètreTypeObligatoireDescription
client_idstringOuiIdentifiant public de l'application cliente.
emailstringOuiEmail de l'utilisateur concerné.
avatarfileOuiFichier image. Formats acceptés : JPEG, PNG, WEBP. Taille max : 2 Mo.

Exemple de requête

Requête (multipart/form-data)
POST /api/user/avatar/upload
Content-Type: multipart/form-data

client_id: axium-stock
email: byao@sifogroup.com
avatar: (fichier binaire, ex: photo.jpg)

Réponses possibles

Cliquez sur un code pour voir le format exact retourné par l'API.

200 OK
{
    "success": true,
    "message": "Avatar mis à jour avec succès.",
    "client": "Axium Stock",
    "user": {
        "id": 1,
        "email": "byao@sifogroup.com",
        "avatar_url": "https://api.identity.optimumci.com/uploads/avatars/0190f3c2-....jpg"
    }
}
Note : avatar_url est une URL directement utilisable dans un <img src="...">. L'ancien avatar de l'utilisateur (s'il existait) est automatiquement supprimé côté serveur.
400 Bad Request
{
    "success": false,
    "message": "Aucun fichier avatar fourni."
}
Le champ avatar est absent de la requête, ou n'a pas été envoyé comme fichier (type File, pas Text).
403 Forbidden
{
    "success": false,
    "message": "Client application invalide."
}
Le client_id envoyé n'existe pas côté AXIUM Identity.
404 Not Found
{
    "success": false,
    "message": "Utilisateur introuvable."
}
Aucun utilisateur ne correspond à l'email fourni.
422 Unprocessable Entity
{
    "success": false,
    "message": "L'image ne doit pas dépasser 2 Mo."
}
Le fichier envoyé dépasse 2 Mo, ou n'est pas dans un format accepté (seuls JPEG, PNG et WEBP sont autorisés). Le message varie selon la cause exacte.

Format des erreurs

Toutes les erreurs retournées par AXIUM Identity utilisent ce format JSON uniforme, quel que soit l'endpoint :

Format commun
{
    "success": false,
    "error": {
        "code": "ERROR_CODE",
        "message": "Message utilisateur",
        "details": []
    }
}
Astuce débutant : testez toujours success en premier dans votre code. S'il vaut false, allez lire error.code (stable, pour votre logique) et error.message (déjà en français, pour l'affichage à l'utilisateur).

Codes d'erreur possibles

CodeStatut HTTPMessageCause
INVALID_CLIENT401Client inconnu.client_id introuvable.
INVALID_CLIENT_SECRET401Client secret invalide.client_secret incorrect pour ce client_id.
AUTHENTICATION_FAILED401Identifiants incorrects.Mot de passe erroné.
AUTHENTICATION_FAILED401Utilisateur invalide.Utilisateur introuvable.
APP_ACCESS_DENIED403Accès refusé. Votre compte ne dispose pas des autorisations requises pour utiliser cette application.Compte valide mais non autorisé sur cette application cliente.

Codes HTTP

CodeDescription
200Opération réussie.
400Requête invalide ou paramètre manquant.
401Authentification échouée ou client invalide.
403Compte ou application non autorisé.
422Fichier invalide (format ou taille non conforme).
500Erreur interne du service AXIUM Identity.
Loading…
Loading the web debug toolbar…
Attempt #