Obexal Docs

Docs/Administration/Journal d'audit

Journal d'audit

Un journal d'audit en ajout seul, borné au tenant : plus d'une centaine d'actions typées, un flux temps réel, un export SIEM et une purge de rétention qui est la seule voie de suppression autorisée.

Tout ce qui compte dans Obexal, d'une connexion à un changement de politique en passant par une délégation d'agent IA, est écrit dans un journal d'audit unique, borné à votre organisation et immuable par construction. Cette page couvre ce qui est journalisé, comment le lire (console, API, flux temps réel), comment l'exporter, et comment fonctionne la rétention.

Ce qui est journalisé

Le journal consigne plus d'une centaine d'actions typées (110 aujourd'hui). Chaque action est un identifiant stable en notation pointée : vos règles SIEM ne dépendent jamais d'un texte d'affichage. Les grandes familles :

FamilleExemples
user.*user.signup, user.login.success, user.login.failed, user.session.revoked
auth.*MFA (auth.mfa.success), passkeys (auth.webauthn.register), passwordless, connexions SAML, LDAP et sociales, resets de mot de passe, auth.account.locked
mfa.*cycle de vie des facteurs : mfa.totp.activate, mfa.recovery.regenerate
oauth.*oauth.consent.granted, oauth.token.exchange (délégation d'agent), oauth.signing_key.rotated
admin.*membres, rôles et groupes, paramètres du tenant, politiques d'accès, blocages d'IP, invitations, domaines personnalisés, jetons d'API, gouvernance des agents (admin.agent.policy_updated, admin.agent.secret_rotated)
scim.*provisioning entrant : scim.user.provisioned, scim.user.deactivated
agents et sécuritéagent.auto_contained, security.incident.acked
plateformetenant.self_signup, operator.tenant.suspended, webhook.endpoint.created, crypto.secrets.reencrypted

Anatomie d'un événement

Tel que retourné par l'API, un événement ressemble à ceci :

{
  "id": "b7f3c2e8-5f9a-4c1d-9e2b-7a6d54c3f0a1",
  "action": "oauth.token.exchange",
  "target": "agent:agent-support-bot",
  "actorUserId": "8c1e35a2-90d7-4b2e-b6a1-53d92f7c44e0",
  "actorEmail": "alice@example.eu",
  "ip": "203.0.113.10",
  "userAgent": "support-bot/1.4",
  "createdAt": "2026-07-02T09:14:03Z",
  "metadata": {
    "agent": "agent-support-bot",
    "agentName": "Support bot",
    "scope": "tickets:read",
    "audience": "https://api.example.eu",
    "chained": false
  }
}

Le champ ip est résolu de façon défensive. Par défaut, c'est l'adresse du pair TCP, non usurpable. X-Forwarded-For n'est honoré que si la connexion provient réellement d'un reverse proxy déclaré dans TRUSTED_PROXIES (auto-hébergement), et c'est alors l'adresse la plus à droite qui n'est pas un proxy de confiance qui est retenue : un client ne peut jamais choisir l'IP qui sera auditée.

Immuable par construction

Le journal est en ajout seul, et cette propriété est appliquée dans la base de données elle-même, pas seulement dans le code applicatif : un trigger sur la table d'audit rejette tout UPDATE et tout DELETE. La seule exception autorisée est le purgeur de rétention, dont le DELETE s'exécute dans une transaction qui pose le drapeau app.allow_audit_purge (SET LOCAL, donc borné à cette seule transaction). Aucun autre chemin de code ne pose ce drapeau.

Consulter le journal

La console affiche le journal dans la section Audit, mise à jour en temps réel. Via l'API, GET /v1/admin/audit exige la permission audit:view, avec un jeton d'API d'administration (Authorization: Bearer obx_...) ou une session de console. Si votre organisation utilise un domaine personnalisé, il remplace accounts.obexal.com.

ParamètreSignification
qrecherche plein texte, limitée à 200 caractères
outcomeok, warn ou danger (toute autre valeur est ignorée)
limittaille de page, 100 par défaut, 500 au maximum
offsetdécalage de pagination
curl -sS "https://accounts.obexal.com/v1/admin/audit?q=agent&outcome=danger&limit=50" \
  -H "Authorization: Bearer $OBEXAL_API_TOKEN"
# 200 -> {"events": [...], "total": 3}

Flux temps réel

GET /v1/admin/audit/stream est un flux Server-Sent Events (SSE) : chaque nouvelle écriture d'audit dans votre organisation pousse un événement audit portant l'entrée en JSON, et un commentaire ping toutes les 25 secondes maintient la connexion. La console s'en sert pour rafraîchir la vue d'audit en direct ; n'importe quel client SSE fonctionne.

curl -N https://accounts.obexal.com/v1/admin/audit/stream \
  -H "Authorization: Bearer $OBEXAL_API_TOKEN"
# : connecté
# event: audit
# data: {"action":"user.login.success","createdAt":"2026-07-02T09:14:03Z", ...}

Exporter vers un SIEM

GET /v1/admin/audit/export?format=csv|json (permission audit:view) retourne une pièce jointe téléchargeable avec les événements les plus récents, plafonnée à 10000. Quand le plafond est atteint, la réponse porte l'en-tête X-Obexal-Truncated: true (et "truncated": true dans le corps JSON) : prenez-le comme un signal d'ingérer plus souvent, pas comme l'historique complet. Les colonnes CSV sont createdAt, action, target, actorUserId, ip, userAgent ; le format JSON inclut aussi metadata.

Pour une ingestion continue, préférez le flux SSE ou des lectures incrémentales périodiques de GET /v1/admin/audit.

Rétention et purge

La rétention est un réglage de déploiement : AUDIT_RETENTION prend une durée, et 0 (le défaut) signifie que rien n'est jamais supprimé. Quand une fenêtre de rétention est définie, un purgeur supprime les entrées plus anciennes que le seuil, une fois au démarrage puis toutes les 24 heures, conformément au principe RGPD de limitation de la conservation. Cette purge est la seule voie autorisée à travers le trigger d'immuabilité, via le drapeau transactionnel app.allow_audit_purge décrit plus haut. Voir Configuration et RGPD.