Provisioning et déprovisioning automatique avec Auth0 et SCIM

Automatiser la création et la suppression des comptes utilisateurs dans Auth0 via SCIM 2.0, webhooks et intégrations RH (Workday, BambooHR).

Par Auth0.Expert · 2025-03-22 · 11 min de lecture

SCIM Provisioning IGA

Provisioning et déprovisioning avec Auth0

TL;DR

Le provisioning manuel des comptes est lent, source d'erreurs et non-conforme. SCIM 2.0 automatise la création, la modification et la désactivation des comptes depuis votre SIRH ou votre annuaire d'entreprise.

---

Architecture JIT (Just-In-Time) vs SCIM

Ce tableau compare les différentes méthodes pour provisionner les comptes utilisateurs dans Auth0.

| Approche | Avantage | Inconvénient | |----------|----------|--------------| | JIT (auto-création au 1er login) | Simple à implémenter | Comptes actifs avant validation | | SCIM (push depuis le SIRH) | Contrôle total, délai minimal | Plus complexe | | Manuel (dashboard) | Contrôle maximal | Lent, source d'erreurs |

Recommandation : SCIM pour les entreprises, JIT pour les SaaS B2C.

---

Implémenter SCIM 2.0 pour Auth0

Ce bloc montre comment exposer des endpoints SCIM 2.0 pour automatiser la gestion des utilisateurs dans Auth0, en garantissant un provisioning et un déprovisioning conforme depuis votre SIRH ou annuaire.

# Endpoints SCIM 2.0 requis
# GET  /scim/v2/Users              → Lister les utilisateurs
# POST /scim/v2/Users              → Créer un utilisateur
# GET  /scim/v2/Users/{id}         → Lire un utilisateur
# PUT  /scim/v2/Users/{id}         → Remplacer un utilisateur
# PATCH /scim/v2/Users/{id}        → Modifier un utilisateur
# DELETE /scim/v2/Users/{id}       → Désactiver (jamais supprimer !)

from fastapi import FastAPI, Request, Header, HTTPException, Depends
import httpx

SCIM_TOKEN = os.environ['SCIM_BEARER_TOKEN']

def verify_scim_token(authorization: str = Header(None)):
    if authorization != f"Bearer {SCIM_TOKEN}":
        raise HTTPException(401, "Token SCIM invalide")

@app.post("/scim/v2/Users", dependencies=[Depends(verify_scim_token)])
async def create_user(request: Request):
    data = await request.json()

    email = data["emails"][0]["value"]
    given_name = data["name"]["givenName"]
    family_name = data["name"]["familyName"]
    department = data.get("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", {}).get("department")

    # Créer dans Auth0
    user = await auth0_create_user({
        "connection": "Username-Password-Authentication",
        "email": email,
        "email_verified": True,
        "given_name": given_name,
        "family_name": family_name,
        "app_metadata": {
            "department": department,
            "provisioned_via": "scim",
            "provisioned_at": datetime.utcnow().isoformat(),
        }
    })

    return {
        "id": user["user_id"],
        "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
        "userName": email,
        "active": True,
        "meta": {
            "resourceType": "User",
            "created": user["created_at"],
            "location": f"/scim/v2/Users/{user['user_id']}",
        }
    }

@app.patch("/scim/v2/Users/{user_id}", dependencies=[Depends(verify_scim_token)])
async def patch_user(user_id: str, request: Request):
    data = await request.json()
    operations = data.get("Operations", [])

    for op in operations:
        if op["op"].lower() == "replace":
            path = op.get("path", "")
            value = op.get("value")

            if path == "active" and not value:
                # Désactivation : bloquer l'utilisateur
                await auth0_block_user(user_id)
            elif path == "active" and value:
                # Réactivation
                await auth0_unblock_user(user_id)

    return {"id": user_id, "active": True}

Cette API SCIM gère la création et la désactivation d'utilisateurs Auth0 en s'appuyant sur des contrôles d'accès sécurisés.

---

Intégration Workday → Auth0

Ce code automatise le provisioning des nouveaux employés depuis Workday vers Auth0, en synchronisant toutes les informations essentielles pour la gestion des comptes et des accès.

# Worker qui lit les nouveaux employés de Workday et les provisionne dans Auth0

import httpx

async def sync_workday_employees():
    """Synchronisation quotidienne Workday → Auth0."""
    # 1. Récupérer les nouveaux employés Workday depuis hier
    employees = await get_workday_new_employees(since=yesterday())

    for emp in employees:
        # 2. Vérifier si le compte Auth0 existe déjà
        existing = await auth0_search_users(f'email:"{emp.work_email}"')

        if not existing:
            # 3. Créer le compte Auth0
            user = await auth0_create_user({
                "email": emp.work_email,
                "email_verified": True,
                "given_name": emp.first_name,
                "family_name": emp.last_name,
                "app_metadata": {
                    "employee_id": emp.id,
                    "department": emp.department,
                    "manager_email": emp.manager_email,
                    "start_date": emp.start_date,
                    "provisioned_via": "workday",
                }
            })

            # 4. Assigner les rôles selon le département
            role_id = DEPARTMENT_ROLES.get(emp.department, DEFAULT_ROLE_ID)
            await auth0_assign_role(user["user_id"], role_id)

            # 5. Envoyer l'email de bienvenue
            await send_welcome_email(emp.work_email, emp.first_name)

Ce worker assure le provisioning automatique des employés avec attribution des rôles et envoi d'un email de bienvenue.

---

Déprovisioning : gestion des départs

Cette routine orchestre la désactivation sécurisée des comptes Auth0 lors du départ d'un collaborateur, en garantissant la conformité et la traçabilité.

# Intégration avec SIRH : départ d'un employé → désactivation Auth0

async def handle_employee_departure(employee_id: str, reason: str):
    """Déprovisionner un utilisateur qui quitte l'entreprise."""

    # 1. Trouver le compte Auth0
    users = await auth0_search_users(f'app_metadata.employee_id:"{employee_id}"')
    if not users:
        return

    user_id = users[0]["user_id"]

    # 2. Révoquer tous les refresh tokens actifs
    await auth0_delete_user_grants(user_id)

    # 3. Bloquer le compte (pas supprimer — garder l'audit trail)
    await auth0_block_user(user_id)

    # 4. Enregistrer la raison du départ
    await auth0_update_metadata(user_id, {
        "blocked_at": datetime.utcnow().isoformat(),
        "blocked_reason": reason,
        "offboarded": True,
    })

    # 5. Alerter le SI pour actions complémentaires
    await notify_it_team(f"Compte désactivé : {users[0]['email']} (raison: {reason})")

    # 6. Archiver les données utilisateur pour conformité
    await archive_user_data(user_id, users[0])

Ce code centralise la désactivation, le blocage et l’archivage des comptes pour une gestion conforme des départs.

---

Just-In-Time Provisioning (SSO enterprise)

Voici comment utiliser une Auth0 Action pour créer et enrichir dynamiquement le compte utilisateur au premier login via SSO, en synchronisant avec le répertoire d'entreprise.

// Action Post Login : créer/synchroniser automatiquement depuis SAML/OIDC
exports.onExecutePostLogin = async (event, api) => {
  // Si c'est la première connexion via SSO enterprise
  if (event.stats.logins_count !== 1) return;

  const namespace = 'https://yourapp.com/';

  // Le SAML/OIDC a rempli le profil automatiquement
  // Compléter avec des données du répertoire d'entreprise
  const directoryUser = await fetch(
    `${event.secrets.DIRECTORY_API}/users/${event.user.email}`,
    { headers: { Authorization: `Bearer ${event.secrets.DIRECTORY_TOKEN}` } }
  ).then(r => r.json()).catch(() => null);

  if (directoryUser) {
    api.user.setAppMetadata('department', directoryUser.department);
    api.user.setAppMetadata('cost_center', directoryUser.costCenter);
    api.user.setAppMetadata('manager_id', directoryUser.managerId);

    // Assigner les rôles selon le groupe LDAP
    const roles = mapLDAPGroupsToRoles(directoryUser.groups);
    api.accessToken.setCustomClaim(`${namespace}roles`, roles);
  }
};

Ce script enrichit le profil utilisateur Auth0 lors de sa première connexion, en lui attribuant données et rôles selon ses groupes LDAP.

---

> 👥 Automatisation provisioning : nous implémentons votre workflow de provisioning/déprovisioning complet (SCIM, SIRH, AD) conforme SOC2 et RGPD.

📞 +33 1 23 45 67 89


Autres articles