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
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.
Autres articles
- Auth0 et OAuth 2.0 : architecture complète pour comprendre les flux d'autorisation
- OpenID Connect sur Auth0 : ID Token, UserInfo et discovery endpoint expliqués
- Configurer SAML 2.0 avec Auth0 : guide complet pour l'entreprise
- Migrer des Rules vers les Auth0 Actions : guide pas à pas
- Architecture multi-tenant avec Auth0 : organisations, isolation et bonnes pratiques
- Validation des JWT Auth0 : RS256 vs HS256, JWKS et pièges communs
- Concevoir son architecture de tenants Auth0 : dev, staging, prod
- Configurer un domaine personnalisé Auth0 : login.votredomaine.com étape par étape