Authagonal
Documentation
Tout ce dont vous avez besoin pour démarrer avec Authagonal — de la création de votre premier locataire à la mise en place du SSO, de SCIM et de l'image de marque personnalisée.
Premiers pas
Authagonal fournit à chaque locataire un serveur OIDC entièrement conforme aux standards. Chaque locataire obtient sa propre URL d'émetteur, son document de découverte et ses points de terminaison de jetons — aucune infrastructure partagée entre les locataires. Vous pouvez passer de zéro à un flux de connexion fonctionnel en moins de 5 minutes.
Créer un tenant
Inscrivez-vous sur authagonal.io et choisissez un slug pour votre tenant. Le slug devient votre domaine d'émetteur : {slug}.authagonal.io. Après avoir créé votre compte, vérifiez votre adresse e-mail pour activer le tenant.


Choisissez un slug unique pour votre tenant lors de l'inscription
Enregistrer un client
Naviguez vers Clients dans la barre latérale du portail et cliquez sur Nouveau client. Entrez un clientId et un clientName pour votre application. Ensuite, dans l'onglet URIs du client, ajoutez au moins une URI de redirection ; c'est là que les utilisateurs sont envoyés après l'authentification. Par exemple : https://app.example.com/callback. Les nouveaux clients exigent un secret client par défaut : pour une application navigateur sans backend, désactivez Exiger un secret dans l'onglet Général.


Enregistrer un nouveau client OAuth dans le portail
Développement local
http://localhost:3000/callback comme URI de redirection pour le développement local. Authagonal autorise les URI de redirection non-HTTPS pour les origines localhost.Votre première connexion
Le moyen le plus rapide de s'intégrer est avec oidc-client-ts, une bibliothèque client OIDC légère pour les applications JavaScript et TypeScript.
import { UserManager } from 'oidc-client-ts';
const mgr = new UserManager({
authority: 'https://acme.authagonal.io',
client_id: 'my-app',
redirect_uri: 'https://app.example.com/callback',
response_type: 'code',
scope: 'openid profile email',
});
// Redirect to login
mgr.signinRedirect();
// On callback page
const user = await mgr.signinRedirectCallback();
console.log(user.profile); // { sub, email, name, ... }Si vous préférez une approche minimale sans bibliothèque, vous pouvez utiliser le flux standard OAuth 2.0 authorization code avec un simple fetch :
// 1. Redirect the user to the authorization endpoint
const authorizeUrl = new URL('https://acme.authagonal.io/connect/authorize');
authorizeUrl.searchParams.set('client_id', 'my-app');
authorizeUrl.searchParams.set('redirect_uri', 'https://app.example.com/callback');
authorizeUrl.searchParams.set('response_type', 'code');
authorizeUrl.searchParams.set('scope', 'openid profile email');
authorizeUrl.searchParams.set('code_challenge', codeChallenge);
authorizeUrl.searchParams.set('code_challenge_method', 'S256');
window.location.href = authorizeUrl.toString();
// 2. On the callback page, exchange the code for tokens
const res = await fetch('https://acme.authagonal.io/connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: new URLSearchParams(window.location.search).get('code')!,
redirect_uri: 'https://app.example.com/callback',
client_id: 'my-app',
code_verifier: codeVerifier,
}),
});
const tokens = await res.json();
// tokens.id_token, tokens.access_token (refresh_token only when offline_access is requested and allowed)

La page de connexion par défaut de votre locataire
Mode bac à sable
{env}-{slug}.authagonal.io, par ex. test1-acme.authagonal.io) et peut être réinitialisé à vide à tout moment sans affecter les utilisateurs en direct.Tableau de bord
Le tableau de bord du portail vous donne un aperçu en temps réel de votre locataire. Il met en évidence les métriques les plus importantes — croissance des utilisateurs, activité d'authentification et navigation rapide vers chaque fonctionnalité du portail.
Vue d'ensemble
En haut du tableau de bord, vous verrez un message de bienvenue et un lien Ouvrir la page de connexion vers la page de connexion hébergée de votre locataire. Sous les cartes de statistiques, une jauge Utilisateurs actifs mensuels suit l'utilisation par rapport à la limite de votre plan et renvoie vers vos options de plan une fois 80 % dépassés. Un graphique Activité de connexion et un fil Activité récente présentant les dernières entrées d'audit complètent la page.


L'écran d'accueil du tableau de bord avec les cartes de statistiques et l'activité de connexion
Métriques d'activité
Six cartes de statistiques résument votre locataire en un coup d'œil :
- Utilisateurs actifs : le nombre total d'utilisateurs de votre locataire
- Connexions (24h) : connexions réussies au cours des dernières 24 heures
- MFA activé : le pourcentage d'utilisateurs ayant activé la MFA, avec le nombre d'utilisateurs inscrits et le total
- Tentatives échouées (24h) : connexions échouées au cours des dernières 24 heures, par exemple identifiants incorrects, comptes verrouillés ou rejets de politique
- Synchronisation SCIM : activité de provisionnement depuis les IdP connectés, affichée comme Inactif ou sous forme de nombre d'opérations
- Dépenses mensuelles : les dépenses depuis le début du mois, avec une projection pour la fin du mois
Les cartes sur 24 heures comparent les dernières 24 heures aux 24 heures précédentes. Le graphique Activité de connexion représente les connexions réussies et échouées par jour sur 14, 30 ou 90 jours. Le tableau de bord s'actualise toutes les minutes.


Cartes de statistiques résumant les dernières 24 heures
Navigation rapide
Sous les métriques, des cartes de navigation renvoient directement vers Clients, SSO, Utilisateurs, SCIM, Identité visuelle, Paramètres, Facturation, Domaines et Journal d'audit. Chaque carte affiche une brève description pour que les nouveaux membres de l'équipe puissent s'orienter rapidement.
Clients
Les clients OAuth représentent les applications qui authentifient les utilisateurs via votre locataire. Chaque client a sa propre configuration pour les URI de redirection, les portées, les types de grants, les durées de vie des jetons et la politique MFA.
Liste des clients
La page Clients affiche un tableau de tous les clients enregistrés. Chaque ligne montre le clientId, le nom d'affichage, les types de grants autorisés sous forme de badges colorés, et si PKCE est activé. Cliquez sur n'importe quelle ligne pour ouvrir l'éditeur de configuration complet.


Liste des clients avec badges de types de grants et indicateurs PKCE
Créer un client
Cliquez sur Nouveau client pour enregistrer une nouvelle application. Vous devez fournir deux champs :
clientId— un identifiant unique pour le client (par ex.my-spa)clientName— un nom d'affichage lisible


Enregistrer un nouveau client OAuth
Supprimer un client
Pour supprimer un client, cliquez sur l'icône de corbeille sur sa ligne dans le tableau des clients et saisissez l'ID du client pour confirmer. Le client est supprimé définitivement et ne peut plus connecter d'utilisateurs ni rafraîchir de jetons. Les jetons d'accès déjà émis ne sont pas révoqués et restent valides jusqu'à leur expiration.
Référence de configuration du client
Chaque client dispose d'un ensemble complet d'options de configuration organisées en cinq onglets : Général, URIs, Scopes & Grants, Tokens et Sécurité.
Paramètres généraux
| Paramètre | Description | Par défaut |
|---|---|---|
clientName | Nom d'affichage visible dans les écrans de consentement et le portail | – |
requirePkce | Exiger Proof Key for Code Exchange sur les flux authorization code | Actif |
requireClientSecret | Exiger un secret client pour les requêtes de jetons (désactiver pour les clients publics comme les SPA) | Actif |
allowOfflineAccess | Autoriser le client à demander des jetons de rafraîchissement via la portée offline_access | Inactif |
alwaysIncludeUserClaimsInIdToken | Inclure les revendications de profil, d'e-mail, de rôles et de groupes dans le jeton ID même lorsque les portées correspondantes n'ont pas été demandées | Inactif |
includeGroupsInTokens | Inclure les noms des groupes SCIM de l'utilisateur en tant que revendication groups, dans les jetons émis lorsque la portée groups est demandée | Inactif |
Sécurité PKCE
URIs
Les champs URI utilisent une saisie par tags — tapez une valeur et appuyez sur Entrée ou virgule pour l'ajouter. Cliquez sur le X d'un tag pour le supprimer.
| Paramètre | Description |
|---|---|
redirectUris | URL de rappel autorisées après l'authentification. Doivent correspondre exactement au paramètre redirect_uri dans les requêtes d'autorisation. |
postLogoutRedirectUris | URL autorisées pour la redirection après déconnexion. |
allowedCorsOrigins | Origines autorisées pour les requêtes cross-origin vers les points de terminaison token et UserInfo. |


Champs de saisie par tags pour la configuration des URIs
Portées et types de grants
| Paramètre | Options |
|---|---|
allowedScopes | openid profile email offline_access phone roles groups |
allowedGrantTypes | authorization_code client_credentials refresh_token urn:ietf:params:oauth:grant-type:device_code urn:ietf:params:oauth:grant-type:token-exchange |
Durées de vie des jetons
| Paramètre | Description | Par défaut |
|---|---|---|
accessTokenLifetimeSeconds | Durée de validité des jetons d'accès | 1800 (30 min) |
identityTokenLifetimeSeconds | Durée de validité des jetons ID | 300 (5 min) |
authorizationCodeLifetimeSeconds | Durée de validité des codes d'autorisation pour l'échange | 300 (5 min) |
absoluteRefreshTokenLifetimeSeconds | Durée de vie maximale d'un jeton de rafraîchissement indépendamment de l'activité | 2592000 (30 jours) |
slidingRefreshTokenLifetimeSeconds | L'expiration du jeton de rafraîchissement est réinitialisé à chaque utilisation, jusqu'à la durée de vie absolue | 1296000 (15 jours) |


Configurer les durées de vie des jetons par client
URI de déconnexion
Les clients peuvent enregistrer des URI de déconnexion back-channel et front-channel. Les deux sont optionnelles — configurez celle qui correspond à la façon dont votre application efface sa session.
| Paramètre | Description |
|---|---|
backChannelLogoutUri | POST serveur à serveur avec un jeton de déconnexion signé. Fiable même si le navigateur est hors ligne. |
frontChannelLogoutUri | Chargée dans un iframe caché lors de la déconnexion pour que le navigateur efface cookies et stockage local. |
frontChannelLogoutSessionRequired | Quand activé, l'URL de déconnexion reçoit les paramètres iss et sid pour que votre app corrèle la déconnexion avec la session spécifique. |
Utilisez les deux
Politique MFA
Chaque client possède sa propre politique MFA, définie dans l'onglet <strong>Sécurité</strong> du client. Le menu déroulant de politique MFA propose trois options :
| Politique | Comportement |
|---|---|
| Désactivé | La MFA n'est jamais demandée pour ce client |
| Activé | Les utilisateurs peuvent s'inscrire optionnellement a la MFA ; ils seront sollicites s'ils sont inscrits |
| Obligatoire | Tous les utilisateurs doivent compléter la MFA pour s'authentifier via ce client |


Politique MFA par client
SSO Entreprise
Le SSO entreprise permet à vos clients d'utiliser leur propre fournisseur d'identité. Authagonal prend en charge la fédération SAML 2.0 et OIDC avec routage par domaine, de sorte que les utilisateurs sont automatiquement diriges vers le bon IdP en fonction de leur adresse e-mail.
Routage SSO par domaine
Connexions SAML 2.0
Pour créer une connexion SAML, naviguez vers la page SSO et sélectionnez l'onglet SAML. Fournissez les informations suivantes :
| Champ | Description |
|---|---|
connectionName | Un nom lisible pour cette connexion (par ex. "Acme Corp Okta") |
entityId | Votre ID d'entité SP. Enregistrez exactement cette valeur chez votre IdP comme identifiant (Entity ID) de l'application ; les assertions doivent la désigner comme Audience |
metadataLocation | URL du document XML de métadonnées SAML de l'IdP |
metadataXml | XML de métadonnées IdP collé, pour les IdP sans URL de métadonnées (Google Workspace) ou dont l'URL n'est pas accessible depuis Internet. Fournissez soit ceci, soit metadataLocation, pas les deux |
nameIdFormat | Format NameID facultatif demandé à l'IdP. Omettez pour le format emailAddress par défaut, ou mettez "none" pour omettre entièrement NameIDPolicy (recommandé pour ADFS) |
allowedDomains | Domaines d'e-mail routés vers cette connexion (par ex. acme.com). Définis via l'API ; le portail les affiche sur la carte de la connexion et dans l'onglet Routage de domaine |
Lorsque vous enregistrez la connexion, Authagonal récupère le document de métadonnées et importe le certificat de signature de l'IdP, l'URL du point de terminaison SSO et le format d'identifiant de nom. Les métadonnées sont périodiquement rafraîchies pour prendre en compte les rotations de certificats.


Créer une connexion SSO SAML 2.0
Connexions OIDC
Pour créer une connexion de fédération OIDC, sélectionnez l'onglet OIDC et fournissez :
| Champ | Description |
|---|---|
connectionName | Un nom lisible pour cette connexion |
metadataLocation | L'URL de découverte OpenID Connect (par ex. https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration) |
clientId | L'identifiant client enregistré auprès de l'IdP externe pour cette fédération |
clientSecret | Le secret client pour l'enregistrement auprès de l'IdP externe |
allowedDomains | Domaines d'e-mail routés vers cette connexion (par ex. acme.com). Définis via l'API ; le portail les affiche sur la carte de la connexion et dans l'onglet Routage de domaine |


Créer une connexion de fédération OIDC
Routage par domaine
Le routage par domaine redirige automatiquement les utilisateurs vers le bon fournisseur d'identité en fonction de leur domaine d'e-mail. Lorsqu'un utilisateur saisit son e-mail sur la page de connexion, Authagonal vérifie si la partie domaine (par ex. acme.com) correspond aux allowedDomains d'une connexion SSO. Si c'est le cas, l'utilisateur est redirigé de manière transparente vers l'IdP de son organisation.
| Domaine d'e-mail | Fournisseur SSO | Protocole |
|---|---|---|
| acme.com | Acme Corp Okta | SAML 2.0 |
| contoso.com | Contoso Azure AD | OIDC |
| example.org | Example OneLogin | SAML 2.0 |


Le routage par domaine associe les domaines d'e-mail aux fournisseurs d'identité
Flux initié par le SP
/saml/{connectionId}/login ou /oidc/{connectionId}/login.Provisionnement JIT
Lorsqu'un utilisateur se connecte via SSO pour la première fois et n'existe pas encore dans votre locataire, Authagonal peut créer automatiquement son compte (provisionnement Just-In-Time). Le provisionnement JIT est désactivé par défaut : activez-le pour chaque connexion en cochant Activer le provisionnement JIT lors de la création de la connexion.
Lorsque le provisionnement JIT est désactivé, seuls les utilisateurs qui ont été pré-provisionnés — via SCIM, la page Utilisateurs du portail ou l'API — peuvent se connecter via cette connexion. Les utilisateurs inconnus reçoivent une erreur access_denied et sont invités à contacter leur administrateur.
Paramètre par connexion
Testez avant le déploiement
Connexions limitées à une organisation
Une connexion peut aussi appartenir à une seule organisation de votre tenant plutôt qu'à l'ensemble du tenant. Elle n'est proposée qu'une fois cette organisation déjà déterminée : par un domaine personnalisé qui lui est rattaché, par un paramètre organization dans le lien de connexion, ou par un client enregistré pour cette seule organisation. Elle n'apparaît jamais sur une page de connexion à l'échelle du tenant. Ces sources sont vérifiées dans cet ordre, la plus prioritaire d'abord.
Se connecter crée l'appartenance
L'unicité des domaines s'applique par périmètre
acme.com peut être routé vers une connexion de tenant et aussi, une fois une organisation déjà sélectionnée, vers la connexion propre à cette organisation. Il ne peut en revanche pas appartenir à deux connexions du même périmètre : Authagonal refuse cela à l'enregistrement de la connexion.Utilisateurs
La page Utilisateurs vous permet de gérer tous les utilisateurs finaux de votre locataire. Vous pouvez rechercher des utilisateurs, voir leurs détails, inviter de nouveaux utilisateurs et voir comment chaque utilisateur a été provisionné.
Recherche et pagination
La barre de recherche trouve un identifiant utilisateur ou un e-mail exact, ou un préfixe de l'e-mail, du prénom ou du nom, et les filtres Tous, Actifs et Inactifs restreignent la liste par statut. La recherche est temporisée (debounce) à 300 ms pour que les résultats se mettent à jour au fil de la saisie sans surcharger l'API. Les résultats sont paginés à 50 utilisateurs par page ; utilisez les contrôles de navigation en bas du tableau pour passer d'une page à l'autre.
Tableau des utilisateurs
Le tableau des utilisateurs affiche les colonnes suivantes pour chaque utilisateur :
| Colonne | Description |
|---|---|
| Utilisateur | Le nom de l'utilisateur (ou son e-mail si aucun nom n'est défini), avec son e-mail en dessous et un badge Non vérifié tant que l'e-mail n'est pas confirmé |
| Statut | Active ou Inactive — indique si le compte est actif |
| Source | SCIM ou Local — comment l'utilisateur a été créé |
| Rôles | Les rôles attribués à l'utilisateur |
| MFA | Enabled lorsque l'authentification multi-facteurs est configurée, sinon un tiret |
| Créé le | La date de création du compte utilisateur |


La liste des utilisateurs avec barre de recherche et pagination
Inviter des utilisateurs
Cliquez sur Inviter un utilisateur pour inviter quelqu'un dans votre locataire. La personne reçoit un e-mail pour définir son propre mot de passe. Le formulaire comprend :
| Champ | Description |
|---|---|
email | L'adresse e-mail de l'utilisateur (doit être unique au sein du locataire) |
firstName | Le prénom de l'utilisateur |
lastName | Le nom de famille de l'utilisateur |
locale | Langue préférée. Définit la langue de l'interface et des e-mails de l'utilisateur ; facultatif, repli sur l'anglais. |
organizationId | Organisation facultative à laquelle ajouter l'utilisateur, avec ses rôles dans celle-ci. Affiché lorsque votre locataire possède des organisations |


Inviter un nouvel utilisateur
Utilisateurs provisionnés par SCIM
Langue préférée
Chaque utilisateur dispose d'une langue préférée qui pilote à la fois son interface hébergée et les e-mails transactionnels qu'Authagonal lui envoie (vérification, réinitialisation de mot de passe, bienvenue, et plus). Vous pouvez la définir lors de l'invitation d'un utilisateur et la modifier à tout moment depuis sa page de détail. Si aucune langue préférée n'est définie, Authagonal se replie sur l'anglais. Le sélecteur propose toutes les langues prises en charge : anglais, chinois (simplifié), allemand, français, espagnol, vietnamien, portugais, japonais, arabe, hindi et afrikaans.


Définir la langue préférée d'un utilisateur sur sa page de détail
Détail de l'utilisateur
Cliquez sur n'importe quelle ligne de la liste des utilisateurs pour ouvrir sa page de détail. De là, vous pouvez modifier les données du profil, gérer les rôles, réinitialiser la MFA, consulter les attributs personnalisés et supprimer l'utilisateur.


Profil
Modifiez l'e-mail, le prénom/nom, le téléphone, l'entreprise, la langue, l'ID externe et l'indicateur actif de l'utilisateur. La modification de l'e-mail ou de l'indicateur d'e-mail confirmé est réservée à un administrateur ou au propriétaire. Les changements d'e-mail doivent rester uniques dans le locataire ; l'API renvoie email_already_in_use s'il est déjà pris.
Rôles
Attribuez et retirez les rôles définis sur la page Rôles. Les rôles attribués sont émis comme revendication roles dans les jetons ID et d'accès lorsque le client demande la portée roles.
Authentification multifacteur
Consultez chaque identifiant MFA enregistré pour l'utilisateur (application d'authentification (TOTP), WebAuthn/passkeys et codes de récupération), chacun avec ses horodatages d'enregistrement et de dernière utilisation. Supprimez des identifiants individuels ou réinitialisez toute la MFA ; ces deux actions sont réservées à un administrateur ou au propriétaire. Réinitialiser force l'utilisateur à s'inscrire à nouveau à sa prochaine connexion.
Attributs personnalisés
Données clé/valeur arbitraires attachées à l'utilisateur. Les clés doivent être uniques. Les attributs sont exposés via l'API de profil utilisateur et SCIM, et peuvent être mappés sur des revendications du jeton d'accès en configurant les userClaims d'une portée personnalisée.
Organisation
L'organisation à laquelle cet utilisateur appartient. C'est un identifiant en texte libre qui vous est propre, émis comme revendication org_id dans ses jetons et sur /connect/userinfo sous la portée profile. Authagonal ne le déduit jamais : il est défini par votre application de provisionnement, par le jeton SCIM qui a créé l'utilisateur, ou à la main ici.
Le lien à côté du champ liste toutes les personnes qui partagent cette valeur, et le même filtre est disponible sur l'API sous la forme GET /api/v1/users?organizationId=. Utilisez-le pour savoir qui appartient à un client final donné sans parcourir tout l'annuaire.
Supprimer l'utilisateur
Supprime définitivement l'utilisateur et toutes ses identifiants MFA. Saisissez l'e-mail de l'utilisateur pour confirmer — aucune annulation possible.
Groupes
Les groupes vous permettent d'organiser les utilisateurs et d'inclure l'appartenance aux groupes dans les jetons. Les groupes peuvent être créés manuellement dans le portail ou provisionnés automatiquement via SCIM depuis un fournisseur d'identité externe.
Liste des groupes
Les groupes sont listés dans l'onglet Groupes de la page SCIM, avec les informations suivantes :
| Colonne | Description |
|---|---|
| Nom du groupe | Le nom d'affichage du groupe |
| Membres | Le nombre d'utilisateurs actuellement dans le groupe |
| Source | SCIM ou Manual — comment le groupe a été créé |
| Créé le | La date de création du groupe |


Liste des groupes avec indicateurs de source
Créer un groupe
Cliquez sur Nouveau groupe et saisissez un Nom d'affichage pour le groupe. Les noms de groupes doivent être descriptifs et uniques au sein de votre locataire (par ex. "Engineering", "Billing Admins", "Beta Testers").
Détail du groupe et membres
Cliquez sur n'importe quel groupe pour ouvrir la vue de détail. Ici, vous pouvez voir tous les membres actuels et gérer l'appartenance :
- Ajouter des membres : recherchez un utilisateur par e-mail ou par nom et ajoutez-le au groupe.
- Supprimer des membres : cliquez sur le bouton de suppression à côté d'un membre et confirmez. Tous les rôles accordés via le groupe sont révoqués.


Gérer l'appartenance au groupe dans la vue de détail
Groupes dans les jetons
Lorsque Groupes dans les tokens est activé sur un client et que la portée groups est demandée, les jetons émis incluent une revendication groups listant les noms d'affichage des groupes de l'utilisateur :
{
"sub": "user-123",
"email": "[email protected]",
"groups": ["Engineering", "Beta Testers"]
}Activer par client
groups.Rôles
Les rôles prennent en charge le contrôle d'accès basé sur les rôles (RBAC) dans votre application. Définissez les rôles dans Authagonal, assignez-les aux utilisateurs et utilisez la revendication roles dans les jetons pour appliquer l'autorisation dans la logique de votre application.
Gestion des rôles
La page Rôles affiche un tableau de tous les rôles définis avec édition en ligne. Chaque rôle possède :
| Colonne | Description |
|---|---|
| Nom | Un identifiant unique pour le rôle (par ex. "admin", "editor", "viewer") |
| Description | Une description lisible de ce que le rôle accorde |
| Créé le | La date de création du rôle |
Créer un rôle
Cliquez sur Nouveau rôle et fournissez un nom et une description. Les noms de rôles doivent être concis et suivre une convention de nommage cohérente dans votre application (par ex. minuscules avec tirets : billing-admin).
Édition en ligne
Les rôles supportent l'édition en ligne directement dans le tableau. Cliquez sur l'icône de crayon sur n'importe quel rôle pour entrer en mode édition — les champs de nom et de description deviennent modifiables. Modifiez les valeurs, puis cliquez sur l'icône de coche pour enregistrer. Les modifications prennent effet immédiatement.
Supprimer un rôle
Cliquez sur l'icône de suppression sur n'importe quel rôle pour le retirer. Une confirmation vous sera demandée avant que le rôle ne soit définitivement supprimé. La suppression d'un rôle n'invalide pas retroactivement les jetons existants — le rôle sera absent des nouveaux jetons émis après la suppression.


Édition en ligne des rôles dans le tableau des rôles
Rôles dans les jetons
Les rôles assignés à un utilisateur sont inclus en tant que revendication roles dans les jetons ID et d'accès lorsque le client demande la portée roles. Votre application peut lire cette revendication pour prendre des décisions d'autorisation :
{
"sub": "user-123",
"email": "[email protected]",
"roles": ["admin", "billing-admin"]
}Provisionnement SCIM
SCIM 2.0 (System for Cross-domain Identity Management) permet le provisionnement automatique des utilisateurs et des groupes depuis les fournisseurs d'identité d'entreprise comme Okta, Azure AD, OneLogin et JumpCloud. Une fois configuré, les comptes utilisateurs et les appartenances aux groupes sont automatiquement synchronisés depuis l'IdP en amont vers votre locataire Authagonal.
Synchronisation du cycle de vie des utilisateurs SCIM avec provisionnement en aval
Étapes de configuration
Suivez ces étapes pour activer le provisionnement SCIM pour un client :
- Sélectionnez l'application cliente — Choisissez le client OAuth auquel le provisionnement SCIM sera associe.
- Générez un jeton SCIM — Fournissez une description et une période d'expiration en jours, puis générez le jeton.
- Copiez le jeton immédiatement — La valeur brute du jeton n'est affichée qu'une seule fois. Copiez-la avant de fermer la boîte de dialogue.
- Configurez votre IdP — Dans les paramètres SCIM de votre fournisseur d'identité, entrez l'URL de base et le jeton bearer.
- Testez la synchronisation des utilisateurs — Déclenchez une synchronisation de test depuis votre IdP et vérifiez que les utilisateurs apparaissent dans le portail Authagonal.
URL de base SCIM
Configurez votre fournisseur d'identité avec l'URL de base suivante :
https://{slug}.authagonal.io/scim/v2Remplacez {slug} par le slug de votre locataire.


Page de configuration SCIM avec génération de jetons
Gestion des jetons
Les jetons SCIM authentifient les requêtes de provisionnement depuis votre IdP. Vous pouvez gérer plusieurs jetons par client :
| Champ | Description |
|---|---|
| Description | Un libellé pour identifier le jeton (par ex. "Okta Production SCIM") |
| Expiration | Durée de vie du jeton en jours (1 à 3650, 365 par défaut). |
| Statut | Les jetons actifs sont en cours d'utilisation. Les jetons révoqués affichent un Revoked badge et ne peuvent plus authentifier les requêtes. |
Pour révoquer un jeton, cliquez sur le bouton Révoquer à côté de celui-ci. Les jetons révoqués restent visibles dans la liste a des fins d'audit mais cessent immédiatement d'accepter les requêtes.


Gestion des jetons avec indicateurs de jetons actifs et révoqués
Copiez le jeton immédiatement
Test de connectivite
Vérifiez que votre intégration SCIM fonctionne en interrogeant le point de terminaison ServiceProviderConfig :
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://acme.authagonal.io/scim/v2/ServiceProviderConfig
Une réponse réussie renvoie un document JSON décrivant les fonctionnalités SCIM prises en charge : PATCH et le filtrage sont pris en charge, contrairement aux opérations en masse, aux changements de mot de passe, au tri et aux ETags.
Langue préférée
preferredLanguage (avec repli sur locale) est mappé à la langue enregistrée de l'utilisateur. Les utilisateurs SSO provisionnés via SCIM reçoivent automatiquement des e-mails localisés dans la langue envoyée par leur IdP.Ce qu'un jeton peut voir
Un jeton SCIM ne voit que les utilisateurs et les groupes qu'il a provisionnés. Lire, mettre à jour ou supprimer un utilisateur créé par un autre connecteur renvoie 404, la liste ne renvoie que les siens, et l'appartenance à un groupe ne peut nommer que des utilisateurs provisionnés par le même connecteur. Les comptes créés par tout autre moyen, par un administrateur, par inscription en libre-service ou par provisionnement juste-à-temps via SSO, sont totalement invisibles pour SCIM.
Cette limite s'applique par client OAuth, et non par jeton. Deux jetons émis pour le même client OAuth forment une seule identité avec deux secrets, et chacun peut modifier ce que l'autre a créé. Donnez un client OAuth distinct à des connecteurs qui ne se font pas mutuellement confiance. externalId a la même portée, donc deux connecteurs peuvent chacun utiliser ext-001 pour des personnes différentes sans entrer en collision.
Déprovisionnement
DELETE /scim/v2/Users/{id} désactive le compte et le marque comme supprimé. L'enregistrement est conservé, comme RFC 7644 l'autorise, mais il répond 404 à toute opération ultérieure et n'apparaît plus dans les listes. Ses inscriptions MFA et ses appartenances aux groupes sont purgées, son association externalId est libérée et tous les jetons émis sont révoqués, de sorte que l'accès prend fin immédiatement et non à la prochaine expiration de jeton.
Si la même personne est réembauchée puis recréée plus tard, elle reçoit un nouvel identifiant utilisateur. Les identifiants ne sont jamais recyclés : l'identifiant est le sujet de chaque jeton que vous avez émis, donc le réutiliser donnerait discrètement au nouvel arrivant l'historique du titulaire précédent dans chaque application qui lui fait confiance.
Marquer les utilisateurs synchronisés avec une organisation
SCIM ne donne à un connecteur aucun moyen d'indiquer lequel de vos clients finaux il synchronise. Le SCIM de base ne définit aucun attribut d'organisation : une simple création d'utilisateur vous donne le nom et l'e-mail de la personne, et rien sur son appartenance. Si plusieurs clients finaux provisionnent dans votre locataire, leurs utilisateurs arrivent impossibles à distinguer.
C'est le jeton qui y répond, et non la requête. Lorsque vous créez un jeton SCIM, choisissez l'une des organisations de votre locataire dans Organisation (le sélecteur apparaît dès que votre locataire possède des organisations). Chaque utilisateur provisionné par ce jeton devient membre actif de cette organisation et la porte ensuite comme revendication org_id dans ses jetons. Émettez un jeton par client final sur le même client OAuth : leurs utilisateurs synchronisés sont alors correctement attribués sans qu'il faille enregistrer un client OAuth pour chacun. Laissez le champ vide et les utilisateurs ne sont pas marqués.
Le marquage n'est pas de l'isolation
Le marquage est appliqué à la création de l'utilisateur et jamais lors d'une mise à jour ultérieure : une synchronisation incrémentale de routine ne peut donc pas déplacer discrètement un compte existant. Si vous exploitez également une application de provisionnement, le marquage explicite du jeton l'emporte : une réponse /try ne remplit qu'une organisation encore vide.
Schémas pris en charge
Nous implémentons les schémas de base User et Group de SCIM 2.0 (RFC 7643). Les attributs utilisateur pris en charge sont userName, name.givenName, name.familyName, displayName, emails, active, externalId et preferredLanguage / locale.
L'extension enterprise user n'est pas implémentée : department, manager, employeeNumber, costCenter, division et organization sont donc acceptés puis ignorés plutôt qu'enregistrés, aussi bien en création qu'en remplacement et en PATCH. Entra et Okta en mappent certains par défaut, vous n'avez donc pas besoin de les retirer de votre mappage d'attributs. Pour rattacher un utilisateur à l'un de vos clients finaux, définissez plutôt l'organisation sur le jeton SCIM : l'attribut enterprise organization est affirmé par le fournisseur d'identité de votre client final, et il ne devient délibérément pas l'org_id de l'utilisateur.
Portées OAuth
Les portées permettent aux clients de demander des portions spécifiques des données ou autorisations d'un utilisateur. Authagonal prend en charge les portées OIDC standards et les portées personnalisées que vous définissez pour vos API.
Portées intégrées
| Portée | Description |
|---|---|
openid | Requis pour tout flux OpenID Connect. Émet un jeton d'identité. |
profile | Retourne les revendications de profil standards (name, given_name, family_name, locale, org_name). |
email | Retourne l'adresse e-mail de l'utilisateur et son statut de vérification. |
phone | Retourne le numéro de téléphone de l'utilisateur (phone_number). |
offline_access | Émet un jeton d'actualisation en plus du jeton d'accès. |
roles | Délivre la revendication roles de l'utilisateur. Sans cette portée, les rôles ne sont pas émis. |
groups | Délivre la revendication groups de l'utilisateur (appartenance aux groupes SCIM). Sans cette portée, les groupes ne sont pas émis. |
Portées personnalisées
Définissez vos propres portées sur la page Portées. Chaque portée décrit une autorisation ou une ressource qu'un client peut demander (par exemple, billing.read, orders.write).


| Champ | Description |
|---|---|
name | L'identifiant de portée envoyé dans les requêtes de jeton (par ex. billing.read). |
displayName | Libellé lisible affiché sur l'écran de consentement. |
description | Explication plus détaillée sous le nom affiché lors du consentement. |
userClaims | Revendications supplémentaires ajoutées au jeton d'accès et au jeton ID quand la portée est accordée. |
showInDiscoveryDocument | Si activé, la portée apparaît dans /.well-known/openid-configuration. |
emphasize | Met en évidence la portée comme sensible sur l'écran de consentement. |
required | Empêche l'utilisateur de désélectionner la portée lors du consentement. |
group | Groupe de consentement : les portées partageant un même intitulé apparaissent ensemble sur l'écran de consentement sous une seule case à cocher. Purement visuel. |
allowedRoles | Rôles qu'un utilisateur doit détenir pour se voir accorder cette portée. Vide, elle est accordée à tous ; un utilisateur ne détenant aucun de ces rôles voit la portée retirée de son jeton au lieu d'être refusé. |
Intégration du consentement
Revendications personnalisées sur les jetons
Les revendications personnalisées ont deux moitiés. La source est constituée de données par utilisateur : chaque AuthUser dispose d'un dictionnaire customAttributes que vous pouvez peupler depuis le portail (Utilisateurs → utilisateur → Attributs personnalisés), via SCIM, ou via un hook de provisionnement TCC. La libération est par portée : la liste userClaims de chaque portée nomme les clés autorisées à quitter le serveur.
Quand un client demande des portées, Authagonal parcourt les portées accordées, fait l'union de leurs listes userClaims et émet uniquement ces clés depuis les customAttributes de l'utilisateur. Les clés inconnues sont silencieusement ignorées — un client ne peut pas lire un attribut en devinant son nom. Les revendications OIDC standard (sub, email, name, etc.) suivent la spécification et ne sont pas soumises à la liste d'autorisation.
# 1. On the user (Portal → Users → {user} → Custom Attributes)
department = "engineering"
employee_id = "E-1042"
seat_tier = "enterprise"
# 2. On a custom scope (Portal → Scopes → projects.read)
name = "projects.read"
userClaims = ["department", "seat_tier"] # <-- whitelist
# 3. Client requests scope=openid projects.read
# Decoded access token (relevant fields only):
{
"sub": "u-9b…",
"scope": "openid projects.read",
"department": "engineering",
"seat_tier": "enterprise"
// employee_id is NOT emitted; it's not in the whitelist for any granted scope.
}Les revendications de fédération comblent les manques par session
department mappé depuis une assertion SAML, passent par la même liste d'autorisation de portée mais ne font que combler les manques : en cas de collision de clé, la valeur persistée de customAttributes l'emporte. Elles sont émises sur les jetons de cette session (et survivent aux rotations de rafraîchissement) sans être réécrites dans l'enregistrement utilisateur.Attribuer des portées aux clients
Ajoutez les portées autorisées dans l'onglet Clients → Portées & Grants. Un client ne peut demander que les portées qui lui ont été accordées ; les portées inconnues sont rejetées avec invalid_scope.
Personnalisation de marque
Personnalisez l'apparence des pages de connexion de votre tenant. Les paramètres de personnalisation vous permettent d'adapter l'expérience d'authentification à l'identité visuelle de votre produit — des logos et couleurs aux remplacements CSS avancés.
Apparence
| Paramètre | Description |
|---|---|
appName | Le nom de l'application affiché dans l'en-tête de la page de connexion (lorsqu'aucun logo n'est défini) et dans les e-mails transactionnels |
logoUrl | URL de votre image de logo. Affichée en haut de la page de connexion. Taille recommandée : 200x60px ou un ratio d'aspect similaire. |
primaryColor | La couleur principale de la marque utilisée pour les boutons, les liens et les états de focus. Définie via un sélecteur de couleur ou une saisie hexadécimale. Un aperçu en direct se met à jour lorsque vous modifiez la valeur. |
customCssUrl | URL d'un fichier CSS chargé après les styles par défaut. Il doit être servi depuis la même origine que la page de connexion ; une URL sur toute autre origine est ignorée. |


Paramètres d'apparence avec aperçu des couleurs en direct
Informations de contact
| Paramètre | Description |
|---|---|
supportEmail | Une adresse e-mail de support affichée sur les pages de connexion. Les utilisateurs la voient lorsqu'ils ont besoin d'aide avec leur compte. |
Options de la page de connexion
Contrôlez les éléments qui apparaissent sur la page de connexion de votre tenant :
| Bascule | Description | Par défaut |
|---|---|---|
showForgotPassword | Afficher le lien "Mot de passe oublié ?" sur le formulaire de connexion | Actif |
showRegistration | Afficher le lien "S'inscrire" pour l'inscription en libre-service | Actif |
poweredBy | Afficher le badge "Propulsé par Authagonal" en bas de la page de connexion | Actif |


Exemple de page de connexion avec personnalisation de marque appliquee
CSS personnalisé
Pour un contrôle total sur l'apparence de la page de connexion, fournissez une URL de fichier CSS dans vos paramètres de charte graphique. Le fichier est chargé après les styles par défaut, vos règles prennent donc le pas. L'URL doit se trouver sur la même origine que la page de connexion ; les feuilles de style d'autres origines ne sont pas chargées.
Propriétés CSS personnalisées
| Variable | Description | Par défaut |
|---|---|---|
--auth-bg | Couleur de fond de la page | #f3f4f6 |
--auth-card-bg | Fond de la carte de connexion | white |
--auth-heading | Couleur du texte de titre | #111827 |
--auth-radius | Rayon de bordure de la carte | 0.5rem |
--auth-font | Police | inherit |
Mode sombre
L'application de connexion propose des thèmes clair, sombre et système. Le paramètre Mode sombre de la page Identité visuelle choisit la valeur par défaut : désactivé, auto (suit la préférence du système, valeur par défaut) ou forcé. Les utilisateurs peuvent toujours choisir via un bouton bascule sur la page de connexion ; le choix est conservé entre les sessions. En mode system, la SPA suit prefers-color-scheme en temps réel.
Les valeurs claires sont déclarées dans :root ; les remplacements sombres sont limités à .dark. Le branding du locataire via customCssUrl prévaut toujours — vos couleurs sont préservées quel que soit le thème choisi par l'utilisateur.
Sélecteurs d'éléments
data-auth. Ces sélecteurs sont stables entre les versions — ils ne casseront pas lorsque nous changerons les noms de classes internes.| Sélecteur | Élément |
|---|---|
[data-auth="page"] | Conteneur d'arrière-plan pleine page |
[data-auth="header"] | Zone du logo et du nom de l'application |
[data-auth="logo"] | Image du logo |
[data-auth="app-name"] | Titre du nom de l'application (lorsqu'aucun logo n'est défini) |
[data-auth="content"] | Zone de contenu principale (formulaires, messages) |
[data-auth="login-form"] | Élément de formulaire de connexion |
[data-auth="email-field"] | Conteneur de la saisie e-mail |
[data-auth="password-field"] | Conteneur de la saisie du mot de passe |
[data-auth="submit-button"] | Bouton de connexion |
[data-auth="languages"] | Barre de sélection de langue |
Paramètres
Configurez les politiques de sécurité, les webhooks et les paramètres d'environnement à l'échelle du tenant. Ces paramètres s'appliquent globalement à tous les clients sauf s'ils sont remplaces au niveau du client.
Politique de mot de passe
Définissez les exigences de complexité des mots de passe pour tous les utilisateurs de votre locataire, sous Utilisateurs → Paramètres :
| Paramètre | Plage | Par défaut |
|---|---|---|
minPasswordLength | 6 — 128 | 8 |
requireUppercase | Actif / Inactif | Actif |
requireLowercase | Actif / Inactif | Actif |
requireDigit | Actif / Inactif | Actif |
requireSpecialChar | Actif / Inactif | Actif |


Configuration de la politique de mot de passe
Politique MFA
La politique MFA à l'échelle du tenant, définie sous Utilisateurs → Paramètres, détermine le comportement par défaut de l'authentification multi-facteurs. Les clients individuels peuvent remplacer ce paramètre.
| Politique | Comportement |
|---|---|
Disabled | La MFA n'est pas disponible. Les utilisateurs ne peuvent pas s'inscrire a la MFA. |
Enabled | La MFA est optionnelle. Les utilisateurs peuvent choisir de s'inscrire et seront sollicites a la connexion s'ils sont inscrits. |
Required | La MFA est obligatoire. Tous les utilisateurs doivent s'inscrire a la MFA et compléter un second facteur à chaque connexion. |
Session et verrouillage
Contrôlez la durée des sessions et le comportement de verrouillage des comptes :
| Paramètre | Plage | Par défaut |
|---|---|---|
sessionLifetimeMinutes | 5 — 43 200 (30 jours) | 60 |
maxFailedAttempts | 1 — 100 | 5 |
lockoutDurationMinutes | 1 — 1 440 (24 heures) | 10 |


Configuration de la session et du verrouillage
Webhooks
Les webhooks vous permettent de réagir aux événements d'authentification en temps réel. Deux événements (onUserAuthenticated, onTokenIssued) sont applicables — par défaut ils se déclenchent de manière asynchrone et ne bloquent pas l'utilisateur, mais vous pouvez activer l'application par événement pour qu'une réponse non 2xx ou un corps {"allow": false} rejette l'action. Les autres événements sont des notifications — toujours fire-and-forget, ne bloquent jamais.
| Événement | Type | Description |
|---|---|---|
onUserAuthenticated | Applicable | Déclenché après une connexion réussie. Par défaut fire-and-forget pour que la latence de connexion ne soit pas affectée. Activez <code>webhookEnforceUserAuthenticated</code> pour le rendre bloquant — une réponse non 2xx ou un corps <code>{"allow": false}</code> rejette alors la connexion. |
onTokenIssued | Applicable | Déclenché avant la création des tokens (authorization_code, refresh_token, client_credentials). Par défaut fire-and-forget. Activez <code>webhookEnforceTokenIssued</code> pour le rendre bloquant — une réponse non 2xx ou un corps <code>{"allow": false}</code> empêche alors l'émission de tokens. |
onUserCreated | Notification | Notification fire-and-forget lorsqu'un nouvel utilisateur s'inscrit ou est provisionné via SCIM. |
onUserUpdated | Notification | Notification fire-and-forget lorsqu'un enregistrement utilisateur est mis à jour (changements de profil, de rôle, mises à jour SCIM). |
onUserDeleted | Notification | Notification fire-and-forget lorsqu'un utilisateur est supprimé, soit via le Portal/SCIM, soit par la politique de rétention. |
onLoginFailed | Notification | Notification fire-and-forget lorsqu'une tentative de connexion échoue en raison d'identifiants incorrects, d'un verrouillage ou d'un rejet de politique. |
Paramètres de webhook supplémentaires :
| Paramètre | Plage | Par défaut | Description |
|---|---|---|---|
webhookTimeoutSeconds | 1 — 30 | 5 | Temps maximum d'attente d'une réponse de webhook d'application avant expiration |
webhookFailOpen | Actif / Inactif | Actif | Lorsqu'activé, si un webhook d'application est injoignable ou expire, l'opération est autorisée à se poursuivre |


Configuration des événements webhook
Disponibilité des webhooks d'application
webhookFailOpen est désactivé, aucun utilisateur ne pourra se connecter. Utilisez le mode fail-open sauf si vous avez des exigences de conformité strictes qui imposent le blocage en cas d'échec du webhook.Vérifier les webhooks
Une fois qu'une URL de webhook est configurée, Authagonal génère un secret de signature propre au tenant (une valeur whsec_… affichée en lecture seule dans Paramètres → Webhooks). Chaque livraison sortante porte un en-tête X-Authagonal-Signature: t=<unix>,v1=<hex>, où v1 vaut HMAC-SHA256(secret, "{t}.{body}") calculé sur le corps brut de la requête. Recalculez-le sur votre point de terminaison et comparez en temps constant pour confirmer que la requête provient réellement d'Authagonal et n'a pas été altérée — et rejetez les livraisons dont le t est trop ancien afin de bloquer les rejeux.
import crypto from 'node:crypto';
// rawBody MUST be the exact bytes Authagonal sent: verify before any JSON re-serialization.
function verifyAuthagonalWebhook(signatureHeader, rawBody, signingSecret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
const { t, v1 } = parts;
// Replay protection: reject deliveries older than 5 minutes.
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto
.createHmac('sha256', signingSecret)
.update(`${t}.${rawBody}`)
.digest('hex');
return v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Faire pivoter le secret de signature
Fenêtre de maintenance
Définissez une fenêtre de maintenance préférée pour les opérations perturbantes telles que le déplacement des données de votre locataire entre shards de stockage. Choisissez une heure UTC (0–23) ; le portail affiche également l'heure équivalente dans votre fuseau horaire local pour plus de commodité.
Inscription et accès
Qui a le droit de devenir utilisateur dans votre tenant, et à quelles conditions ces personnes peuvent se connecter.
| Paramètre | Par défaut | Description |
|---|---|---|
| Inscription publique | Actif | Indique si n'importe qui peut s'inscrire soi-même. La désactiver masque la page d'inscription et fait rejeter l'API d'inscription, ce qui compte : masquer uniquement le lien laisserait le point de terminaison ouvert. Utilisez-la quand vous provisionnez vous-même les utilisateurs via SCIM, l'API ou des invitations. |
| Exiger la vérification de l'e-mail pour se connecter | Actif | Une adresse non confirmée ne peut pas se connecter. Désactivez ce paramètre si c'est votre propre application qui contrôle la vérification ; dans les deux cas, la revendication email_verified reste présente dans le jeton, vous conservez donc le signal. |
| Enregistrement dynamique de clients | Inactif | Permet à un client de s'enregistrer lui-même à l'exécution selon la RFC 7591, ce dont un agent IA ou un connecteur MCP a besoin avant de pouvoir démarrer un flux. Inactif par défaut, et son activation n'ouvre la porte que pour votre tenant. Les enregistrements restent dans tous les cas soumis à une limitation de débit, à PKCE et au consentement. |
| Politique MFA du portail | Désactivé | L'authentification multifacteur pour votre propre équipe qui se connecte au portail, définie indépendamment de la politique appliquée à vos utilisateurs finaux. Désactivée, proposée à la connexion, ou obligatoire. |
| Nombre maximal d'utilisateurs | Aucun | Par défaut, il n'y a aucun plafond sur le nombre total d'utilisateurs, et aucun plan n'en impose. Tant que l'adresse e-mail du propriétaire du locataire n'est pas vérifiée, un plafond temporaire de 5 utilisateurs s'applique ; il est levé définitivement une fois l'adresse vérifiée. |
Rétention des utilisateurs inactifs
Désactivez puis supprimez, si vous le souhaitez, les comptes restés inutilisés, pour qu'un annuaire n'accumule pas indéfiniment des identités dormantes. Les deux sont inactifs tant que vous ne les définissez pas, et la suppression est définitive.
| Paramètre | Par défaut | Description |
|---|---|---|
| Désactiver après (jours d'inactivité) | Jamais | Désactive un compte qui ne s'est pas connecté depuis cette durée. L'enregistrement est conservé et peut être réactivé. |
| Supprimer après (jours d'inactivité) | Jamais | Supprime définitivement le compte. Il n'y a aucune annulation possible, définissez donc la fenêtre d'avertissement et le webhook ci-dessous avant d'activer ce paramètre. |
| Jours d'avertissement | 7 | Combien de jours avant une désactivation ou une suppression le webhook d'avertissement se déclenche, ce qui vous laisse le temps d'intervenir. |
| Webhook de rétention | - | L'endroit où ces avertissements et les actions exécutées sont postés, pour que vous puissiez prévenir la personne ou maintenir le compte ouvert. |
Export d'audit et sauvegardes distantes
Deux façons de faire sortir vos données de façon planifiée plutôt qu'à la demande. L'export d'audit envoie chaque journée révolue d'événements d'audit vers une URL que vous désignez, signée pour que vous puissiez vérifier qu'elle vient de nous, afin d'alimenter un SIEM ou une archive de conformité. Les sauvegardes distantes envoient des copies de vos sauvegardes quotidiennes et hebdomadaires vers une destination que vous contrôlez, sans authentification, avec une authentification basique ou avec un jeton bearer. L'export d'audit se configure dans l'onglet Export de la page Journal d'audit et les sauvegardes distantes sur la page Sauvegardes ; les deux vous appartiennent, indépendamment des sauvegardes que nous conservons.
Environnements bac à sable
La page Environnements gère les environnements bac à sable : des environnements nommés et isolés, avec leurs propres utilisateurs, clients, clés de signature, inscriptions MFA et grants, chacun accessible à une URL distincte. L'identité visuelle, le plan et la facturation sont partagés avec la production. Utilisez-les pour tester les modifications de configuration, les intégrations SSO et les points de terminaison webhook sans affecter les utilisateurs en direct. Vous pouvez en créer jusqu'à 5 par défaut, et les utilisateurs actifs des bacs à sable comptent dans votre MAU.
| Action | Description |
|---|---|
| Ajouter un environnement | Crée un nouvel environnement. Le nom comporte de 1 à 20 lettres minuscules et chiffres, et "live" est réservé. L'environnement démarre vide : rien n'est copié depuis la production. |
| Actualiser | Efface les données de l'environnement et le remet à vide. |
| Supprimer | Supprime définitivement l'environnement bac à sable et toutes ses données. |
Chaque environnement est accessible à {name}-{slug}.authagonal.io.


Contrôles de l'environnement bac à sable
Facturation
Gérez votre abonnement et votre facturation via la page Facturation du portail. Cette page vous donne un aperçu de votre plan actuel et fournit l'accès au portail de facturation Stripe pour gérer les moyens de paiement, les facturés et les changements de plan.
Informations d'abonnement
La page de facturation affiche les détails de votre abonnement actuel en un coup d'oeil. Vous verrez un badge de statut indiquant l'état de votre abonnement — active, trialing, past_due, canceled ou unpaid — ainsi que le nom de votre plan, la période de facturation actuelle (dates de début et de fin), et si votre abonnement est configuré pour s'annuler a la fin de la période en cours.
Gérer l'abonnement
Cliquez sur le bouton Gérer l'abonnement pour ouvrir le portail de facturation Stripe dans une nouvelle fenêtre. De la, vous pouvez mettre à jour vos moyens de paiement, consulter et télécharger les facturés, changer de plan ou annuler votre abonnement.
Si aucun abonnement n'existe encore, un bouton Configurer la facturation est affiché à la place, qui vous guide dans le choix d'un plan et la saisie des informations de paiement.


La page de facturation affiche les détails de votre abonnement actuel et fournit l'accès à Stripe
Sécurité des paiements
Domaines personnalisés
Servez vos pages d'authentification depuis votre propre domaine (par ex. auth.votredomaine.com) au lieu du domaine par défaut {slug}.authagonal.io. Les domaines personnalisés offrent à vos utilisateurs une expérience d'authentification transparente et personnalisée.
Ajouter un domaine
Entrez le nom d'hôte que vous souhaitez utiliser dans le formulaire d'ajout de domaine (par ex. auth.votredomaine.com). Une fois ajouté, le domaine apparaîtra dans votre liste de domaines avec le statut pending_verification.
Vérification DNS
Créez les deux enregistrements CNAME que le portail affiche pour le domaine, pointant tous deux vers {slug}.authagonal.io : l'un sur le nom d'hôte lui-même, qui sert le trafic et peut être proxifié, et l'autre sur _authagonal-challenge. suivi du nom d'hôte, qui prouve la propriété et doit être en DNS uniquement (non proxifié). Une fois les enregistrements en place, cliquez sur Vérifier DNS pour lancer la vérification. Les domaines en attente sont également revérifiés automatiquement.
auth.yourdomain.com. CNAME acme.authagonal.io. _authagonal-challenge.auth.yourdomain.com. CNAME acme.authagonal.io.
Propagation DNS
Certificats TLS
Une fois votre domaine vérifié, vous avez besoin d'un certificat TLS pour que les utilisateurs puissent se connecter en toute sécurité via HTTPS. Authagonal prend en charge deux options :
Automatique (cert-manager) — Authagonal provisionné et renouvelle automatiquement les certificats TLS avec cert-manager. C'est l'option recommandée pour la plupart des utilisateurs. Aucune configuration supplémentaire n'est requise.
Apportez le votre (BYO) — Téléchargez votre propre certificat et clé privée au format PEM. Cette option est utile si votre organisation exige des certificats d'une autorite de certification spécifique. L'expiration du certificat est suivie pour que vous puissiez le renouveler avant qu'il n'expire.
Statut du domaine
Chaque domaine affiche un badge de statut indiquant son état actuel : pending_verification (DNS non encore confirmé), verified (DNS confirmé, TLS en attente) ou active (entièrement opérationnel).


La liste des domaines affiche chaque domaine personnalisé et son statut actuel


Téléchargez votre propre certificat TLS et clé privée au format PEM
Renouvellement de certificat BYO
Organisations
Une organisation est un client à l'intérieur d'un tenant. Le tenant reste la frontière d'isolation : un préfixe de table et une clé de signature, chaque hôte du tenant étant son propre émetteur. Une organisation partitionne l'identité au sein du tenant, de sorte qu'un seul tenant peut servir de nombreuses organisations clientes sans un tenant par client.
Les organisations coexistent avec les domaines personnalisés (un domaine peut être rattaché à une organisation) et les applications de provisionnement (une application de provisionnement peut associer une organisation à un nouvel utilisateur). Consultez le guide Applications multi-clients pour le schéma complet « un tenant, de nombreux clients à leur image » pour lequel cette fonctionnalité existe.
Modèle et identifiants
Chaque organisation possède un id stable et immuable (de la forme org_<32 hex>) émis dans la revendication de jeton org_id, ainsi qu'un slug immuable et unique au sein du tenant, émis dans org_slug et accepté par le paramètre d'autorisation organization. Les identifiants et les slugs partagent un même espace de recherche : un slug égal à l'identifiant d'une autre organisation est refusé comme collision, exactement comme un slug en double ordinaire.
| Champ | Modifiable | Description |
|---|---|---|
id | Non | La revendication org_id. Généré sous la forme org_ + un GUID : le tiret bas n'est pas valide dans un slug, donc un nouvel identifiant ne peut jamais entrer en collision avec un slug. |
slug | Non | La revendication org_slug, et ce qu'accepte le paramètre organization. Immuable, car une partie utilisatrice (relying party) l'écrit en dur. |
name | Oui | La revendication <code>org_name</code>. Librement modifiable. |
metadata | Oui | Paires clé/valeur libres, contrôlées par le tenant. Jamais émises dans un jeton, sauf si l'ensemble de revendications d'une portée en libère explicitement une. |
brandingJson | Oui | Objet JSON fusionné champ par champ sur l'image de marque du tenant. Voir Personnalisation de l'image de marque ci-dessous. |
domains | Points de terminaison de domaine uniquement | Les domaines de messagerie que l'organisation a revendiqués, chacun avec l'enregistrement DNS qui le prouve. Modifiés uniquement via les points de terminaison de domaine ci-dessous, jamais par une mise à jour. |
Appartenances
Une appartenance est la jointure plusieurs-à-plusieurs entre un utilisateur et une organisation : une ligne par paire (organisation, utilisateur). Un utilisateur peut en avoir plusieurs ; c'est la ligne d'appartenance, et non l'ancienne étiquette d'organisation par utilisateur, qui autorise la connexion en tant que l'organisation.
| Statut | Donne droit à des jetons ? |
|---|---|
invited | Invité mais pas encore accepté. N'autorise pas l'émission de jetons. |
active | Un membre en règle. Le seul statut qui autorise l'émission de jetons. |
suspended | Appartenance retirée sans supprimer l'enregistrement. N'autorise pas l'émission de jetons. |
Les roles d'une appartenance sont tirés du catalogue de rôles existant du tenant et réunis dans la revendication roles, mais seulement lorsque l'organisation a été explicitement sélectionnée par la requête (voir Sélection de l'organisation pour le jeton) et uniquement à partir d'une ligne d'appartenance active. Un rôle détenu dans une organisation n'atteint jamais un jeton émis pour une autre.
Inviter dans une organisation
POST /api/v1/users/invite accepte les paramètres facultatifs organizationId et organizationRoles. Un seul appel crée le compte avec une appartenance invited et envoie un e-mail d'invitation reprenant l'image de marque de l'organisation. Le lien s'ouvre sur le domaine personnalisé rattaché à l'organisation, s'il en a un. Lorsque la personne accepte, l'appartenance devient active. Désigner une organisation nécessite d'être propriétaire ou administrateur.
Provisionnement SCIM dans une organisation
Un jeton SCIM peut être lié à une organisation (organizationId sur POST /api/v1/scim/tokens, ou le sélecteur Organisation lors de la création d'un jeton). L'identifiant doit désigner une organisation du tenant. Chaque utilisateur créé par ce jeton devient membre active et porte l'organisation en tant que org_id. La liaison s'applique uniquement à la création, et elle détermine l'appartenance, pas l'accès : deux jetons sur un même client voient toujours les utilisateurs l'un de l'autre. Supprimer un utilisateur, par quelque voie que ce soit, supprime ses appartenances.
Indicateurs de politique
enabled (activé par défaut) : une organisation désactivée n'émet plus de jetons pour elle-même, vérifié à l'autorisation et à chaque renouvellement. La désactiver interrompt donc les sessions en cours à leur prochaine rotation, et pas seulement les nouvelles connexions.
requireMembershipForTokens (activé par défaut) : indique si un utilisateur doit détenir une appartenance active pour recevoir un jeton pour cette organisation. Il ne s'applique qu'à une sélection explicite (une requête désignant l'organisation, un renouvellement qui la porte, une connexion limitée à une organisation, ou un client restreint à une seule). Une organisation simplement héritée de l'ancienne étiquette du compte n'est jamais soumise à cet indicateur.
allowAutoMembership (désactivé par défaut) permet à un utilisateur de rejoindre l'organisation sans invitation lorsque son adresse e-mail confirmée appartient à l'un des domaines vérifiés de l'organisation. Appliqué à l'autorisation et à chaque renouvellement. Voir Domaines de messagerie et appartenance automatique ci-dessous.
Domaines de messagerie et appartenance automatique
Une organisation revendique un domaine de messagerie et prouve qu'elle le contrôle avec un enregistrement DNS TXT. Avec allowAutoMembership activé, un utilisateur dont l'adresse e-mail confirmée appartient à ce domaine devient membre dès sa première connexion en tant qu'organisation.
- Le revendiquer.
POST /api/v1/organizations/{id}/domainsavec le domaine. La réponse est201avecrecordName(_authagonal-org.acme.com) etrecordValue(authagonal-org-verify=<token>). Le jeton est aléatoire et propre à chaque revendication. - Publier l'enregistrement. Ajoutez un enregistrement TXT avec ce nom et cette valeur exacte dans le DNS du domaine.
- Le vérifier.
POST /api/v1/organizations/{id}/domains/{domain}/verifyrecherche l'enregistrement. Une correspondance renvoie200avecverified: true. Un échec renvoie409 verification_failed, jamais200avecverified: false, afin qu'un client qui interroge en boucle ne puisse pas confondre un échec avec un succès. - Le supprimer.
DELETE /api/v1/organizations/{id}/domains/{domain}renvoie204. Les appartenances existantes sont conservées ; seules les futures adhésions automatiques cessent.
POST /api/v1/organizations/org_7fa2c9e1.../domains
Content-Type: application/json
{ "domain": "acme.com" }
201 Created
{
"domain": "acme.com",
"verified": false,
"verifiedAt": null,
"createdAt": "2026-10-03T01:02:03Z",
"recordName": "_authagonal-org.acme.com",
"recordValue": "authagonal-org-verify=Qm9...base64url"
}Refus : 400 domain_invalid (pas un simple nom DNS), 409 domain_exists (déjà sur cette organisation), 409 domain_taken (une autre organisation du tenant le détient), 404 organization_not_found et 404 domain_not_found. Un domaine appartient à une seule organisation au plus par tenant, et cela est revérifié au moment de la vérification.
La règle d'appartenance automatique
Le sélecteur admet un utilisateur qui ne détient aucune appartenance active lorsque toutes les conditions suivantes sont réunies :
- L'organisation a été explicitement sélectionnée : un renouvellement qui la porte, une connexion limitée à une organisation, le paramètre
organization(un domaine rattaché le fournit), ou un client restreint à exactement une organisation. L'ancienne étiquette du compte n'entraîne jamais d'adhésion automatique. - L'organisation est activée et
allowAutoMembershipest activé. - L'e-mail de l'utilisateur est confirmé, car n'importe qui peut s'inscrire en tant que
[email protected]. - La partie de l'e-mail après son dernier
@, en minuscules, est exactement égale à l'un des domaines vérifiés de l'organisation. Il n'y a pas de correspondance de sous-domaine : unacme.comvérifié n'admet pas[email protected]. Revendiquez et vérifiez chaque sous-domaine séparément.
Ce qu'elle écrit, avant l'exécution de la barrière d'appartenance : l'absence de ligne devient une nouvelle appartenance active sans rôle ; une ligne invited est promue en active avec ses rôles conservés ; une ligne active est laissée telle quelle ; une ligne suspended n'est jamais promue.
Supprimer un membre ne l'empêche pas de revenir
allowAutoMembership est activé, un membre supprimé qui remplit toujours les conditions rejoint de nouveau l'organisation à sa prochaine autorisation ou à son prochain renouvellement. Pour tenir à l'écart un utilisateur qui remplit les conditions, passez son appartenance à suspended, le seul état que la règle ne modifie jamais.Sélection de l'organisation pour le jeton
L'organisation à laquelle une requête se résout est décidée à un seul endroit, de sorte que la réponse est identique sur /connect/authorize, à chaque renouvellement et sur le flux d'appareil (device grant). Priorité, de la plus haute à la plus basse :
| N° | Source | Comportement |
|---|---|---|
| 1 | Grant transmis (renouvellement) | L'organisation pour laquelle un jeton antérieur a été émis. Si elle n'existe plus, le renouvellement lui-même est refusé plutôt que de se rabattre sur autre chose. |
| 2 | Connexion limitée à une organisation | La session s'est connectée via une connexion SAML ou OIDC appartenant à une organisation, donc cette organisation est sélectionnée. C'est la seule source qui est prouvée plutôt qu'affirmée. Une requête qui nomme une autre organisation est refusée, tout comme une connexion dont l'organisation n'existe plus. |
| 3 | organization | Résolu d'abord par slug, puis par identifiant. Un domaine rattaché atteint cette même branche : le middleware l'ajoute avant l'évaluation de la requête. Une organisation nommée mais introuvable est un refus net, jamais un repli silencieux. |
| 4 | Client restreint à exactement une organisation | Sélection automatique : une application propre à un client enregistre une fois son unique organisation et n'envoie jamais de paramètre. Un client restreint à <em>plusieurs</em> organisations sans indication est refusé avec <code>account_selection_required</code>. |
| 5 | Ancienne étiquette d'organisation du compte | Une simple chaîne, résolue par identifiant en une seule recherche, et non par un parcours des appartenances de l'utilisateur. Si elle ne désigne aucune ligne d'organisation réelle, elle est émise telle quelle, sans contrôle, exactement comme avant l'existence des organisations. Ce n'est jamais une sélection explicite, donc elle n'entraîne jamais d'adhésion automatique. |
| 6 | Aucune des sources ci-dessus | Aucune organisation sur le jeton : ni revendication <code>org_id</code>, ni <code>org_slug</code>, ni <code>org_name</code>. |
Les appartenances ne servent jamais d'indice
requireMembershipForTokens est vérifié et, s'il s'applique, où une adhésion automatique est tentée.Rattachement de domaine
Un domaine personnalisé peut être rattaché à une organisation, ce qui en fait la porte d'entrée propre de cette organisation. Le rattachement est appliqué par le middleware de résolution du tenant, à la fois pour GET /connect/authorize (ajouté à la chaîne de requête) et pour POST /connect/par (le corps poussé est réécrit à la place, car PAR lit ses paramètres depuis la charge utile stockée). Voir Domaines personnalisés pour le mécanisme complet.
PUT /api/v1/custom-domains/auth.acme.com/organization
Content-Type: application/json
{ "organizationId": "org_7fa2c9e1..." }Un domaine rattaché refuse une requête contradictoire
400 access_denied, avant l'affichage de toute page de connexion. Sans cela, une partie utilisatrice pourrait envoyer son propre paramètre organization et le rattachement serait purement décoratif.Connexions limitées à une organisation
Une connexion SAML ou OIDC peut appartenir à une organisation. Se connecter par son intermédiaire sélectionne cette organisation et crée une appartenance active lorsque l'utilisateur n'en a pas. Une ligne invited est acceptée : elle devient active et conserve ses rôles et son invitant, de sorte qu'un invité qui se connecte via son IdP n'a jamais besoin de l'e-mail. Un membre suspended reste suspendu et est refusé à l'émission du jeton. Cela ne dépend ni de allowAutoMembership ni des domaines, car l'organisation a déjà été choisie par la connexion.
Le nom de l'organisation sur la page de connexion
La page de connexion affiche Connexion à {name} sous le nom de l'application. Le nom provient de la même organisation que celle dont provient l'image de marque de la page : l'organisation du domaine rattaché, puis celle nommée par la requête d'autorisation, puis l'unique organisation restreinte du client. Il est masqué lorsqu'il n'y a pas d'organisation, ou lorsque le nom de l'organisation est égal au nom de l'application, afin que l'en-tête n'affiche jamais « Acme / Connexion à Acme ».
Personnalisation de l'image de marque
Le brandingJson d'une organisation est fusionné champ par champ sur l'image de marque du tenant pour la page de connexion : une clé présente et non nulle remplace, une clé absente ou nulle hérite, et une clé inconnue est ignorée. Un JSON mal formé retombe sur l'image de marque propre du tenant avec un avertissement journalisé, jamais sur un échec de chargement de la page.
L'onglet Image de marque modifie les 21 champs fusionnables : apparence (appName, logoUrl, primaryColor, customCssUrl), couleurs des modes clair et sombre, couleurs des e-mails, supportEmail, showForgotPassword, poweredBy et languages. Chaque champ hérite soit de la valeur du tenant, affichée en indication, soit la remplace, avec une commande Effacer qui supprime la clé.
showRegistration ne peut pas être remplacé
Reprise depuis l'ancienne étiquette d'organisation
Avant l'existence des organisations, un utilisateur pouvait porter une étiquette d'organisation en texte libre sans aucun enregistrement derrière. POST /api/v1/organizations/backfill la migre vers de vraies organisations et appartenances, regroupées par valeur historique distincte. Il s'agit d'une simulation, sauf si le corps est { "dryRun": false }.
- Borné : analyse au plus 50 000 utilisateurs par appel. Une réponse
truncatedsignifie qu'il faut le relancer ; les utilisateurs déjà migrés sont ignorés lors de la nouvelle exécution. - Idempotent : une valeur historique distincte déjà migrée est reconnue par un marquage interne, et non par le nom d'affichage (modifiable) de l'organisation. Renommer ensuite l'organisation obtenue ne crée donc pas de doublon à l'exécution suivante.
{
"dryRun": true,
"organizationsCreated": 3,
"membershipsCreated": 41,
"usersSkipped": 0,
"organizations": [
{ "legacyValue": "acme-corp", "slug": "acme-corp", "users": 22 }
],
"truncated": false
}Présentation de l'interface du portail
La page Organisations liste toutes les organisations du tenant, 50 à la fois avec un bouton Charger plus, et propose Nouvelle organisation (slug et nom uniquement ; les indicateurs de politique, les domaines et l'image de marque se définissent ensuite) ainsi qu'un flux Remplir à partir du champ d'organisation hérité qui exécute la reprise ci-dessus en aperçu, puis Appliquer.


La liste des organisations affiche chaque organisation cliente du tenant avec son slug, son nom et sa date de création
La page de détail de chaque organisation comporte trois onglets : Général (nom, slug en lecture seule, les trois interrupteurs de politique, une carte Domaines de messagerie pour ajouter, vérifier et supprimer des domaines de messagerie et copier l'enregistrement TXT, et une suppression qui demande de saisir le slug pour confirmer), Marque (chaque champ remplaçable, héritant de la valeur du tenant ou la remplaçant) et Membres (ajout par e-mail, avec une invitation proposée lorsqu'aucun compte n'existe, changement de statut et suppression par ligne, avec Charger plus).


L'onglet Membres liste chaque appartenance avec son statut et une commande par ligne pour la modifier ou la supprimer


L'onglet Image de marque remplace champ par champ l'image de marque de la page de connexion du tenant pour cette organisation
La page Domaines propose le sélecteur domaine → organisation : chaque carte de domaine comporte une liste déroulante intégrée énumérant les organisations du tenant plus une option « Locataire (aucun) » qui supprime le rattachement, appliquée immédiatement au changement. Le même sélecteur apparaît lors de l'ajout d'un domaine.


Le sélecteur d'organisation intégré à une carte de domaine rattache ce domaine personnalisé à une organisation
Événements d'audit
organization.created · organization.updated · organization.deleted · organization.member.added · organization.member.invited · organization.member.joined · organization.member.updated · organization.member.removed · organization.domain_added · organization.domain_verified · organization.domain_removed · organization.backfill · domain.organization_set
Pagination
La liste des organisations et celle des membres sont paginées par curseur et répondent { items, nextCursor }. Passez limit (50 par défaut, borné de 1 à 200) et, après la première page, le nextCursor de la réponse précédente tel quel en tant que cursor. Un nextCursor nul indique la dernière page. Le curseur est une position d'ensemble de clés opaque sur l'identifiant de l'organisation (ou de l'utilisateur pour les membres), de sorte qu'ajouter ou supprimer des lignes entre deux appels ne peut ni décaler ni répéter une page. Un curseur que la liste n'a pas émis donne 400 invalid_cursor.
Gérer les organisations depuis un assistant IA
Le MCP du portail hébergé expose treize outils d'organisation, tous nécessitant le rôle d'administrateur du tenant : lister, obtenir, créer, mettre à jour et supprimer des organisations ; lister, ajouter, mettre à jour et retirer des membres ; ajouter, vérifier et supprimer des domaines de messagerie ; et lister les organisations d'un utilisateur. Ils appellent les mêmes opérations que l'API ci-dessus, de sorte qu'un outil ne peut pas diverger de sa route. Voir Piloter votre portail depuis un assistant IA.
Un émetteur par hôte
Chaque hôte d'un tenant est son propre émetteur OIDC. Lorsque l'hôte de la requête a été résolu via la table de domaines du tenant, l'émetteur et chaque URL de point de terminaison annoncée par la découverte est https://{host} : chaque domaine personnalisé actif affirme donc son propre iss, et l'hôte canonique du tenant reste inchangé. Les clés de signature sont propres au tenant, donc chaque hôte sert le même jeu de clés. C'est ce qui permet à un seul tenant de servir plusieurs clients, chacun sur son propre domaine à son image rattaché à sa propre organisation. Voir Domaines personnalisés.
Configuration des e-mails
Configurez la façon dont votre locataire envoie les e-mails transactionnels, comme les e-mails de vérification, de réinitialisation de mot de passe et d'invitation. Choisissez entre l'expéditeur partagé par défaut, un domaine personnalisé vérifié via Resend, ou votre propre serveur SMTP.


E-mails localisés
Les e-mails transactionnels sont envoyés dans la langue préférée du destinataire. Les e-mails de vérification, de réinitialisation de mot de passe, de compte existant, de bienvenue, d'invitation, de suppression de compte, de support et de facturation sont disponibles en onze langues : anglais, allemand, français, espagnol, portugais, vietnamien, chinois simplifié, japonais, arabe, hindi et afrikaans. Lorsqu'aucun modèle n'existe pour la langue du destinataire, l'e-mail se replie sur l'anglais.
La langue est résolue à partir de la préférence enregistrée du destinataire au moment de l'envoi. Cette préférence peut provenir de plusieurs sources :
- Inscription et enregistrement — capturée à partir de la langue choisie par l'utilisateur sur les écrans de connexion hébergés.
- La page Utilisateurs du portail — définie par un administrateur lors de la création ou de la modification d'un utilisateur.
- Le provisionnement SCIM : mappé depuis le
preferredLanguage(oulocale) de l'IdP lorsque les utilisateurs sont synchronisés via SCIM. - La page de compte en libre-service — choisie par l'utilisateur lui-même sur
/login/account.
Aucune configuration nécessaire
Fournisseurs d'e-mails
| Fournisseur | Description | Configuration |
|---|---|---|
| Authagonal (Default) | E-mails envoyés depuis [email protected] via notre infrastructure Resend partagée. | Aucune configuration nécessaire — fonctionne immédiatement. |
| Custom Domain (Resend) | E-mails envoyés depuis votre propre domaine vérifié via Resend. | Enregistrez votre domaine, ajoutez les enregistrements DNS, vérifiez la propriété. |
| Custom SMTP | E-mails envoyés via votre propre serveur SMTP. | Fournissez l'hôte, le port, les identifiants et les paramètres TLS du SMTP. |
Identité de l'expéditeur
L'e-mail et le nom de l'expéditeur sont partagés entre tous les modes de fournisseur. L'e-mail de l'expéditeur est requis pour les fournisseurs Domaine personnalisé (Resend) et SMTP personnalisé ; à défaut, le nom de l'expéditeur revient au nom d'application défini dans l'identité visuelle.
| Champ | Description |
|---|---|
emailSenderEmail | L'adresse From des e-mails sortants. Doit être sur un domaine vérifié en mode Domaine personnalisé (Resend). |
emailSenderName | Nom d'affichage visible dans la boîte de réception du destinataire. |
Domaine personnalisé Resend
Vérifiez votre domaine d'envoi auprès de Resend une seule fois, puis utilisez-le comme adresse d'expéditeur pour ce locataire. Les enregistrements DNS (SPF, DKIM) sont affichés dans le panneau Domaine d'envoi personnalisé de Paramètres → E-mail ; Resend les contrôle lorsque vous cliquez sur <strong>Vérifier</strong>.
SMTP personnalisé
Apportez votre propre serveur SMTP — utile pour les relais internes, les prestataires non pris en charge par Resend, ou la conformité réglementaire.
| Champ | Description |
|---|---|
smtpHost | Nom d'hôte du serveur SMTP (ex. smtp.example.com). |
smtpPort | Port de connexion, 587 par défaut. TLS est négocié via STARTTLS ; le TLS implicite sur le port 465 n'est pas pris en charge. Utilisez 25 pour les relais internes sans authentification. |
smtpUsername | Nom d'utilisateur d'authentification (facultatif — laissez vide pour les relais sans authentification). |
smtpPassword | Mot de passe d'authentification. Stocké chiffré dans le secret de configuration du locataire. |
smtpUseTls | Exiger TLS. Laissez activé sauf si vous ciblez un relais interne de confiance. |
Domaine d'envoi personnalisé
Avec le fournisseur Domaine personnalisé (Resend), vous pouvez enregistrer votre propre domaine pour que les e-mails proviennent de votre marque (par ex. [email protected]) au lieu de @authagonal.io.
- Allez dans Paramètres → E-mail et sélectionnez le fournisseur Domaine personnalisé (Resend).
- Saisissez votre nom de domaine et cliquez sur Enregistrer le domaine.
- Ajoutez les enregistrements DNS affichés (DKIM, SPF et return path) au DNS de votre domaine.
- Cliquez sur Vérifier la vérification — une fois le DNS propagé (généralement 1 à 10 minutes), le statut du domaine passera à vérifié.
Propagation DNS
Tests
Utilisez le bouton Envoyer un e-mail de test dans Paramètres → E-mail pour vérifier votre configuration. Un e-mail de test sera envoyé à votre adresse d'administrateur avec les paramètres enregistrés.
Journal d'audit
Le journal d'audit fournit un enregistrement en lecture seule de toutes les actions administratives effectuées sur votre locataire. Chaque modification effectuée via le portail ou l'API est capturée avec un contexte complet, vous offrant une piste complète pour la conformité et le dépannage.
Colonnes du journal
| Colonne | Description |
|---|---|
| Horodatage | La date et l'heure à laquelle l'action a eu lieu |
| Acteur | L'adresse e-mail de l'administrateur qui a effectué l'action, ou "system" pour les actions automatisées |
| Action | Le type d'action effectuée (par ex. Client créé, Paramètres mis à jour) |
| Entité | La cible de l'action au format type:id (par ex. client:my-app) |
| Détail | Contexte supplémentaire sur la modification |
Actions suivies
Les actions administratives suivantes sont enregistrées dans le journal d'audit :
| Catégorie | Actions |
|---|---|
| Clients | Client créé, Client mis à jour, Client supprimé |
| Connexions SSO | Connexion SAML créée, Connexion SAML supprimée, Connexion OIDC créée, Connexion OIDC supprimée |
| Utilisateurs | Utilisateur créé, Utilisateur mis à jour |
| Paramètres | Paramètres mis à jour, Personnalisation mise à jour |
| Domaines | Domaine ajouté, Domaine vérifié, Domaine supprimé |
| SCIM | Jeton SCIM créé, Jeton SCIM révoqué |
| Rôles | Rôle créé, Rôle mis à jour, Rôle supprimé |
| Groupes | Groupe créé, Groupe supprimé |
| Équipe | Membre d'équipe invité, Membre d'équipe supprimé |


Le journal d'audit fournit un enregistrement complet de toutes les actions administratives
Rétention
Sauvegardes
Authagonal sauvegarde automatiquement les données de votre locataire toutes les heures. Les sauvegardes incluent tous les utilisateurs, groupes, rôles, clients, connexions SSO, jetons SCIM, la charte graphique et les paramètres. Vous pouvez consulter l'historique et télécharger la dernière sauvegarde complète depuis la page Sauvegardes.


Fonctionnement des sauvegardes
- Une fois par jour, les sauvegardes incrémentielles horaires sont consolidées en une nouvelle sauvegarde complète, et le dimanche les sauvegardes complètes quotidiennes sont consolidées en une sauvegarde hebdomadaire. Sept sauvegardes quotidiennes et quatre hebdomadaires sont conservées.
- Les sauvegardes incrémentielles s'exécutent toutes les heures, ne capturant que les lignes modifiées depuis la dernière sauvegarde.
- Les sauvegardes sont stockées dans Azure Blob Storage avec la même identité gérée que celle de votre locataire.
- Les enregistrements supprimés sont suivis via des tombstones et inclus dans les sauvegardes à des fins d'audit.
Téléchargement des sauvegardes
Cliquez sur « Télécharger la dernière » pour obtenir un fichier ZIP contenant la sauvegarde complète la plus récente fusionnée avec toutes les sauvegardes incrémentielles suivantes. Chaque table est exportée en fichier JSONL (un objet JSON par ligne).
Format de sauvegarde
Applications de provisionnement
Les applications de provisionnement sont vos propres services. Authagonal les appelle à chaque création d'un utilisateur, afin qu'elles puissent créer un compte, attribuer une licence, décider à quelle organisation appartient l'utilisateur, ou refuser purement et simplement l'inscription.
Comment ca fonctionne
Lorsqu'un utilisateur est créé, Authagonal appelle l'URL de callback de votre application de provisionnement selon le modèle TCC (Try/Confirm/Cancel). Chaque application doit accepter pendant la phase Try avant qu'aucune ne soit validée. Plusieurs systèmes en aval peuvent ainsi se mettre d'accord, ou l'un d'eux opposer son veto, sans laisser de comptes à moitié créés.
| Phase | Point de terminaison | Objectif |
|---|---|---|
| /try | POST {callbackUrl}/try | Vérifié si l'application peut traiter l'utilisateur. Renvoie 200 pour accepter ou 4xx pour rejeter. |
| /confirm | POST {callbackUrl}/confirm | Valide l'opération après que toutes les applications ont accepte la phase /try. |
| /cancel | POST {callbackUrl}/cancel | Annule l'opération si une autre application échoue pendant la phase /try. |
Quand le provisionnement s'exécute
Le provisionnement s'exécute sur chaque chemin qui crée un utilisateur, pas uniquement l'inscription en libre-service. Les combinaisons application et utilisateur déjà provisionnées sont ignorées, si bien qu'une application voit chaque utilisateur une seule fois.
| Chemin de création | Quand il se déclenche |
|---|---|
POST /api/auth/register | Inscription en libre-service |
| Callback SAML ACS | Première connexion SSO d'un nouvel utilisateur (JIT) |
| Callback OIDC | Première connexion SSO d'un nouvel utilisateur (JIT) |
POST /scim/v2/Users | Un connecteur provisionne un utilisateur depuis l'annuaire du client |
| Création d'utilisateur dans le portail et l'admin | Un opérateur crée ou invite un utilisateur manuellement |
La requête Try
Authagonal envoie ce JSON en POST à <code>{callbackUrl}/try</code>. Les champs sans valeur sont omis plutôt qu'envoyés à null.
| Champ | Type | Description |
|---|---|---|
transactionId | string | Identifie cette transaction de provisionnement. La même valeur est envoyée à /confirm et /cancel : préparez votre travail sous cette valeur, puis validez-le ou abandonnez-le lorsque cet appel arrive. |
userId | string | L'identifiant Authagonal de l'utilisateur. C'est le subject que vous verrez dans ses tokens. |
email | string | L'adresse e-mail de l'utilisateur. |
firstName | string | Prénom, lorsque le chemin de création en a fourni un. |
lastName | string | Nom de famille, lorsque le chemin de création en a fourni un. |
organizationId | string | L'organisation à laquelle l'utilisateur appartient déjà, le cas échéant. Présent uniquement si quelque chose lui en a déjà attribué une. Lors d'une première inscription, le champ est absent : c'est le signal pour en attribuer une. |
customAttributes | object | Les attributs personnalisés enregistrés de l'utilisateur. Pour un utilisateur créé par SSO, ils incluent federated_connection, le nom de la connexion qui s'est portée garante de lui. |
Le cas courant à anticiper est celui d'un utilisateur qui arrive par SSO : il n'a pas encore d'organisation, et federated_connection vous indique de quel client il provient.
{
"transactionId": "8f14e45fceea167a5a36dedd4bea2543",
"userId": "0f6b1c8e-3d2a-4f51-9e77-2c1a4b5d6e7f",
"email": "[email protected]",
"firstName": "Ada",
"lastName": "Lovelace",
"customAttributes": {
"federated_connection": "acme-okta"
}
}La réponse Try
Votre application répond avec un 200 et un corps JSON. Ce corps n'est pas une simple confirmation : c'est par lui qu'une application en aval attribue l'organisation et les attributs qui finiront dans les tokens de l'utilisateur.
| Champ | Type | Description |
|---|---|---|
approved | boolean | Indique si cette application accepte l'utilisateur. Vaut true par défaut si le champ est omis. False rejette l'inscription et le nouveau compte est supprimé. |
reason | string | Pourquoi l'utilisateur a été rejeté. Cette valeur est renvoyée à l'appelant du chemin de création. |
organizationId | string | L'organisation à laquelle appartient cet utilisateur. Elle est enregistrée sur l'utilisateur et émise sous forme de claim org_id dans ses tokens. Elle n'est appliquée que si l'utilisateur n'en a pas déjà une : la première application qui répond l'emporte, et les applications suivantes voient cette attribution. |
customAttributes | object | Attributs à fusionner sur l'utilisateur, clé par clé. Ils sont émis dans les tokens via la configuration UserClaims d'un scope. |
emailVerified | boolean | Votre application garantit qu'elle a vérifié cette adresse, par exemple par l'utilisation d'une invitation qui y a été envoyée. Authagonal marque le compte comme confirmé et n'envoie pas son propre e-mail de vérification. |
{
"approved": true,
"organizationId": "org_acme",
"customAttributes": { "org_role": "member" }
}C'est d'ici que vient org_id
org_id lorsqu'une requête ne désigne aucune organisation, est exactement ce que votre application de provisionnement a renvoyé comme organizationId. Lorsqu'il s'agit de l'id d'une organisation du tenant, les tokens portent les org_id, org_slug et org_name de cette organisation, et une organisation désactivée refuse la connexion. Toute autre valeur est émise telle quelle comme org_id, sans règle d'unicité ni contrainte de format. Renvoyer un id d'organisation ne crée pas d'appartenance. Vous pouvez aussi le définir directement avec PUT /api/v1/users/{userId}, et filtrer dessus avec GET /api/v1/users?organizationId=.Associer les utilisateurs à la bonne organisation
Décidez de l'organisation ici, à un seul endroit, plutôt qu'à chaque chemin de création. Un utilisateur SSO transporte federated_connection, qui identifie la connexion l'ayant authentifié et donc le client, et qui reste juste lorsqu'un même client fédère plusieurs domaines de messagerie. Un utilisateur invité n'a pas de connexion : rattachez-le grâce à l'invitation que vous avez émise. Les deux chemins atteignent /try avant que l'utilisateur n'existe, donc une seule logique les couvre et il n'y a pas deux règles susceptibles de diverger.
// POST {callbackUrl}/try
app.post('/provisioning/try', async (req, res) => {
const { email, customAttributes } = req.body;
// An SSO user carries the connection that vouched for them. That is the
// customer, and it stays right when one customer has several domains.
const connection = customAttributes?.federated_connection;
const org = connection
? await orgByConnection(connection)
: await orgByPendingInvite(email);
if (!org) return res.json({ approved: false, reason: 'No organization for this user' });
// Stamped on the user and emitted as org_id on every token from now on.
res.json({ approved: true, organizationId: org.id });
});Un rejet supprime le compte
approved: false, l'utilisateur qui vient d'être créé est supprimé afin qu'aucun compte à moitié provisionné ne subsiste. Les chemins de création de l'API renvoient 422 avec votre reason ; les callbacks SAML et OIDC renvoient 400. Renvoyez approved: true pour un utilisateur pour lequel vous n'avez rien à faire.Ajouter une application de provisionnement
Pour ajouter une application de provisionnement, fournissez un Nom de l'application, une URL de callback, une Clé API optionnelle et un Timeout du Try optionnel (en secondes, 60 par défaut, de 5 à 300 ; Confirm et Cancel utilisent un délai court fixe). La clé API est envoyée en tant que jeton Bearer dans l'en-tête Authorization de chaque requête webhook, permettant à votre application d'authentifier les requêtes provenant d'Authagonal.
Test
Cliquez sur Tester à côté de n'importe quelle application de provisionnement pour envoyer une requête de test à votre URL de rappel. Les résultats du test affichent le code de statut HTTP et le corps de la réponse, vous aidant à vérifier que votre application reçoit et traite correctement les webhooks.


Testez les applications de provisionnement pour vérifier la livraison et le traitement des webhooks
Limites du plan
Le nombre maximum d'applications de provisionnement est configurable par locataire, avec une limite par défaut de 6. Cette limite peut être ajustée par un administrateur si votre workflow nécessite des cibles de provisionnement supplémentaires.
Authentification par clé API
Équipe
La page Équipe gère les administrateurs du portail : les personnes qui peuvent accéder à votre locataire et le configurer via le portail de gestion. Chaque membre de l'équipe a un rôle (Owner, Admin, Developer ou Support) qui détermine ce qu'il peut modifier.
Liste des administrateurs
La liste des administrateurs affiche le nom, l'adresse e-mail, le rôle et la date d'ajout de chaque membre de l'équipe. Un indicateur "Vous" est affiché à côté de la ligne de l'utilisateur actuel pour que vous puissiez facilement identifier votre propre compte.
Inviter des administrateurs
Pour inviter un nouveau membre de l'équipe, fournissez son adresse e-mail, son nom et son rôle. Il reçoit un e-mail contenant un lien pour définir son mot de passe et activer son compte ; le lien est valable 7 jours.
Champs d'invitation
Les invitations d'administrateur créent un compte en attente et envoient à l'invité un lien d'activation par e-mail.
| Champ | Description |
|---|---|
email | Adresse e-mail du nouvel admin. Doit être unique dans le locataire. |
name | Nom affiché dans la liste des administrateurs. |
role | Rôle à accorder : tenant:admin, tenant:developer ou tenant:support. tenant:admin par défaut. Le rôle Owner ne peut pas être accordé par invitation. |
Supprimer des administrateurs
Le propriétaire du locataire peut cliquer sur Retirer à côté de n'importe quel membre de l'équipe pour révoquer son accès. Une boîte de dialogue de confirmation s'affiche avant que le retrait ne soit finalisé. Vous ne pouvez pas vous retirer vous-même, et le locataire conserve toujours son propriétaire.


Gérez les administrateurs du portail depuis la page Équipe
Propriété
Support
Ouvrez un ticket de support auprès de l'équipe Authagonal sans quitter le portail. Chaque ticket est une conversation en fil de discussion, pour que vous et notre équipe restiez sur la même longueur d'onde, du premier signalement à la résolution.
Vos tickets
La page de support liste tous les tickets que vous avez ouverts, l'activité la plus récente en premier. Utilisez le badge de statut pour voir d'un coup d'œil ce qui attend une action de votre part et ce qui est entre nos mains.


Vos tickets de support avec objet, statut, priorité et dernière activité
- Chaque ligne affiche l'objet, le statut actuel (ouvert, en attente, résolu ou fermé), la priorité et l'heure de la dernière activité.
- Cliquez sur Nouveau ticket pour en ouvrir un, puis donnez-lui un objet, une priorité et votre premier message.
- Les badges de statut à code couleur permettent de repérer facilement dans la liste les tickets qui requièrent votre attention.
Un fil de ticket
Ouvrir un ticket affiche la conversation complète. Les réponses s'ajoutent dans l'ordre, et les nouveaux messages de notre équipe apparaissent sans recharger la page.


Un fil de ticket entre vous et l'équipe Authagonal
- Les messages en fil entre vous et l'équipe Authagonal sont affichés dans l'ordre chronologique.
- Répondez directement dans le fil et joignez des fichiers pour partager des logs, des captures d'écran ou votre configuration.
- Le fil se met à jour en direct, donc une réponse de notre équipe apparaît dès qu'elle est envoyée.
- Si vous répondez plutôt à un e-mail de notification, votre message est ajouté au fil automatiquement.
Comment les réponses vous parviennent
Service de support pour vos utilisateurs
Distinct du support que vous obtenez auprès de nous, Authagonal peut faire tourner un service de support pour vos utilisateurs finaux. Ils ouvrent des tickets depuis les pages de leur compte, sur l'hôte à votre image propre à votre tenant, et votre équipe y répond depuis le portail.
Il existe parce que les personnes qui n'arrivent pas à se connecter sont précisément celles qui ne peuvent pas atteindre un outil de support exigeant une connexion. Le service se trouve à côté des écrans de connexion : un utilisateur bloqué garde donc une voie d'accès, et chaque ticket arrive déjà rattaché à un compte réel de votre annuaire plutôt qu'à l'adresse que quelqu'un a saisie.
L'activer
Ouvrez Support client dans le portail, passez à son onglet Paramètres et activez Activer le support client. Cet onglet est disponible pour le propriétaire et les administrateurs. Rien n'est visible pour vos utilisateurs tant que vous ne l'avez pas fait.
| Paramètre | Ce que cela fait |
|---|---|
| Activer le support client | L'interrupteur principal. Inactif, les pages destinées aux utilisateurs finaux et la boîte de réception de vos opérateurs sont masquées, et leurs API répondent 404. |
| Autoriser les demandes des visiteurs déconnectés | Permet à un visiteur non connecté d'ouvrir un ticket, ce qui est le cas de l'utilisateur bloqué. Protégé par une vérification anti-robot, et l'échange se poursuit ensuite par e-mail et via un lien privé, puisqu'il n'y a aucun compte auquel se connecter. |
| Notifications par e-mail | Qui reçoit un e-mail quand un ticket arrive ou qu'un utilisateur répond : personne, des adresses précises ou toute votre équipe de support (Owner, Admin et Support), pour que personne n'ait à surveiller la boîte de réception. |
| Langue par défaut des clients | La langue supposée pour un utilisateur lorsque nous ne connaissons pas encore la sienne, pour ses tickets et ses e-mails. La langue enregistrée par l'utilisateur l'emporte toujours, et sans réglage c'est l'anglais. Ce paramètre se trouve dans l'onglet <strong>Général</strong> des Paramètres. |
| URL du webhook de support | Une URL vers laquelle poster en POST les événements de ticket, pour les pousser dans vos propres outils. |
Non disponible sur le plan Gratuit
Ce que vos utilisateurs voient
Les utilisateurs connectés disposent d'un espace de support dans les pages de leur compte, sur l'hôte de votre tenant et à votre image. Ils peuvent ouvrir un ticket, consulter tout ce qu'ils ont ouvert et répondre dans un fil. Les réponses de votre équipe arrivent aussi par e-mail, un utilisateur n'a donc pas besoin de revenir vérifier en permanence.
Avec les tickets anonymes activés, quelqu'un qui ne peut pas se connecter peut tout de même en ouvrir un. Il indique une adresse e-mail et son message, et reçoit en retour un lien privé vers la conversation. Ce lien est la seule voie d'entrée, traitez-le donc comme un secret d'authentification : il est impossible à deviner, et toute personne qui le détient peut lire ce fil précis et y répondre.
La boîte de réception des opérateurs
Votre équipe répond depuis Support client dans le menu latéral du portail. C'est un espace distinct de vos propres tickets ouverts chez nous, et il est accessible à partir du rôle tenant:support, ce qui vous permet de donner à un agent l'accès au service de support sans lui donner le reste du portail.
| Action | Ce que cela fait |
|---|---|
| Répondre | Publier dans le fil. L'utilisateur reçoit un e-mail et voit la réponse en direct si la page est ouverte. |
| Assigner | Confier un ticket à un membre nommé de votre équipe, pour que deux personnes ne répondent pas au même. |
| Statut et priorité | Faire passer un ticket par les statuts ouvert, en attente, résolu et fermé, et indiquer son degré d'urgence. Les tickets fermés sont supprimés après une période de rétention plutôt que conservés indéfiniment. |
| Notes internes | Des notes visibles uniquement par votre équipe, jamais par l'utilisateur. Les modifications et les suppressions sont consignées dans le journal d'audit. |
| Ouvrir au nom d'un utilisateur | Démarrer un fil avec l'un de vos utilisateurs en le choisissant dans votre annuaire, pour les cas où la conversation a commencé ailleurs. |
| Escalader vers Authagonal | Si un ticket concerne finalement Authagonal plutôt que votre produit, escaladez-le. Cela ouvre un ticket lié auprès de notre équipe, en emportant si vous le souhaitez le fil déjà écrit, et relie les deux pour que vous puissiez suivre l'un et l'autre. Un ticket ne peut être escaladé qu'une seule fois. |
Les utilisateurs écrivent dans leur propre langue
Un ticket est stocké dans la langue dans laquelle l'utilisateur l'a écrit, et chaque personne du fil le lit dans la sienne. Votre agent voit un message traduit dans la langue de son portail, l'utilisateur voit votre réponse traduite dans la sienne, et le texte original est toujours conservé à côté. La langue est détectée à partir du premier message puis fixée sur le ticket. Les traductions sont calculées une fois par langue et réutilisées, un long fil ne se retraduit donc pas lui-même.
Fuseaux horaires
Un ticket enregistre le fuseau horaire depuis lequel l'utilisateur l'a ouvert. Chaque message affiche ensuite son heure locale à côté de la vôtre, si bien qu'une réponse à 14:32 se lit comme le 02:32 qu'elle était réellement pour la personne qui l'attendait. Rien n'est affiché quand le fuseau est inconnu, par exemple pour un ticket arrivé par e-mail, ou quand il correspond au vôtre.
Webhooks
Définissez une URL de webhook de support pour recevoir les événements de ticket au fil de l'eau, afin de déclencher une alerte ou de recopier les tickets dans votre propre système. Les charges utiles sont signées pour que vous puissiez vérifier qu'elles viennent bien de nous.
| Événement | Ce que cela fait |
|---|---|
support.ticket.created | Un utilisateur a ouvert un ticket. |
support.ticket.message | Un message a été publié dans un fil, par un utilisateur ou par l'un de vos opérateurs. Le champ fromStaff de la charge utile indique lequel. |
support.ticket.status_changed | Le statut d'un ticket a changé, par exemple en résolu. |
support.ticket.assigned | Un ticket a été assigné à un membre de l'équipe. |
Importer et migrer
Migrez un système d’identité existant vers votre locataire Authagonal. Deux sources sont prises en charge — Duende IdentityServer (une base SQL Server) et Auth0 (la Management API). Chacune exécute un aperçu en lecture seule pour que vous vérifiiez exactement ce qui sera copié avant de valider.
Importation depuis Duende IdentityServer
Migrez les clients, portées, utilisateurs et rôles d'une base SQL Server Duende IdentityServer existante vers votre locataire Authagonal. L'importation se déroule en deux phases — aperçu et validation — afin que vous puissiez vérifier ce qui sera copié avant toute modification.
Ce qui est importé
L'importateur lit la ConfigurationDb de Duende et les tables ASP.NET Identity, puis écrit les lignes mappées dans votre locataire. Les artefacts à courte durée de vie (persisted grants, device codes, clés de signature) sont ignorés.
| Entité | Tables sources | Notes |
|---|---|---|
| Clients | Clients, ClientSecrets, ClientGrantTypes, ClientScopes, ClientRedirectUris | Les clients désactivés sont importés désactivés. Les secrets expirés sont ignorés. |
| Portées | ApiScopes, ApiResources, IdentityResources | Les mappings de claims utilisateur sont préservés lorsqu'ils sont reconnus. |
| Utilisateurs | AspNetUsers, AspNetUserClaims | Les empreintes de mot de passe (ASP.NET Identity V3) sont copiées telles quelles et ré-hashées à la première connexion. |
| Rôles | AspNetRoles, AspNetUserRoles | Les affectations de rôles sont préservées. |
| Connexions externes | AspNetUserLogins | Conservées pour référence ; reconnectez les IdP amont via SSO après l'import. |
Aperçu avant validation
Collez votre chaîne de connexion ConfigurationDb / IdentityDb de Duende puis cliquez sur Lancer l’aperçu. L'aperçu ouvre une connexion en lecture seule et compte chaque ligne qui serait importée. Aucune écriture n'a lieu.
- Décomptes d'entités pour clients, portées, utilisateurs, rôles et affectations de rôles.
- Avertissements de collision lorsque le locataire cible possède déjà des clients (les ClientIds correspondants sont écrasés), des rôles ou des portées (les noms correspondants sont ignorés).
- Avertissements pour les tables inconnues et colonnes non mappées afin que vous sachiez ce qui sera abandonné.


Panneau d'aperçu avec décomptes et avertissements
Empreintes de mot de passe
Duende stocke les mots de passe au format ASP.NET Identity V3 (PBKDF2). Le PasswordHasher d'Authagonal vérifie directement ce format et réhash vers le format natif à la première connexion réussie — les utilisateurs conservent leur mot de passe existant sans flux de réinitialisation.
Réconciliation des ID utilisateur
Si un utilisateur déjà présent dans ce locataire a la même adresse e-mail qu'un enregistrement entrant, l'import bascule le userId de ce compte vers le sub source avant l'importation, afin que les rôles, connexions et revendications importés soient rattachés au compte existant et que les applications qui référencent déjà l'utilisateur par leur sub source continuent de résoudre après la bascule. Le mot de passe et le profil existants du compte sont préservés ; les rôles source viennent s'ajouter par-dessus. L'aperçu liste chaque compte qui sera réconcilié avant que vous ne validiez.
Exécuter l'importation
Cliquez sur Démarrer l’import après avoir vérifié l'aperçu. La phase de validation écrit les clients, portées, utilisateurs, rôles et références de connexion externe dans les stores de votre locataire. Les clients ayant un clientId correspondant sont écrasés ; les lignes ayant un scope name, un email ou un role name correspondant sont ignorées, ce qui permet de relancer l'importateur sans risque.
Ce qui n'est pas importé
- Persisted grants, device codes, sessions côté serveur — courte durée de vie, régénérés automatiquement.
- Clés de signature — Authagonal émet ses propres clés par tenant.
- Colonnes et tables personnalisées — tout ce qui dépasse le schéma standard de Duende remonte en avertissement afin que vous sachiez que ces données sont abandonnées.
- Clients désactivés — importés à l'état désactivé ; réactivez-les depuis la page Clients quand vous êtes prêt.
Indisponible en sandbox
Importer depuis Auth0
Connectez Authagonal à la Management API de votre locataire Auth0 et transférez vos applications, APIs, rôles, utilisateurs et connexions d’entreprise. Les identifiants d’utilisateur et d’application importés sont conservés, de sorte que les références sub et client_id existantes continuent de se résoudre après la bascule.
Ce dont vous aurez besoin
Créez une application Machine-to-Machine dans Auth0 autorisée pour la Management API, avec ces portées de lecture : read:users, read:clients, read:resource_servers, read:roles, read:connections, read:client_grants. Collez son domaine, son client ID et son client secret dans le formulaire d’import — ils ne servent qu’à l’import.
Ce qui est importé
| Entité | Tables sources | Notes |
|---|---|---|
| Applications | clients, client-grants | Public vs. confidential est détecté automatiquement. Les client secrets sont ré-hashés pour continuer à fonctionner. |
| APIs et portées | resource-servers | Les audiences et portées sont attribuées à chaque client à partir de ses grants. |
| Rôles | rôles + attributions | Les attributions de rôles par utilisateur sont conservées. |
| Utilisateurs | users + identities | Les profils et métadonnées sont transférés ; les identités sociales/d’entreprise deviennent des connexions liées. |
| Connexions | connections (OIDC) | Les connexions OIDC d’entreprise deviennent des providers fédérés. Les connexions SAML, sociales et base de données sont ignorées avec un avertissement. |
Mots de passe
La Management API d’Auth0 ne renvoie jamais les empreintes de mot de passe. Si vous disposez de l’export groupé de mots de passe assisté par le support Auth0 (NDJSON), fournissez-le — les empreintes bcrypt sont importées telles quelles et vos utilisateurs conservent leur mot de passe sans réinitialisation. Ce fichier contient aussi l’intégralité de vos utilisateurs, levant la limite de 1 000 utilisateurs du listing de l’API Auth0. Sans lui, les utilisateurs sont importés sous forme de profils et définissent un nouveau mot de passe à la première connexion.
Mêmes aperçu, rotation et limites
Référence API
Chaque locataire expose un serveur OIDC conforme aux standards à l'adresse https://{slug}.authagonal.io. Tous les points de terminaison suivent les spécifications OAuth 2.0 et OpenID Connect. Cette référence couvre chaque point de terminaison avec lequel votre application peut avoir besoin d'interagir.
Flux Authorization Code avec PKCE
Découverte OIDC & JWKS
Le document de découverte permet aux bibliothèques clientes OIDC de se configurer automatiquement. Aucune authentification n'est requise pour ces points de terminaison.
GET /.well-known/openid-configuration
Renvoie le document de configuration du fournisseur OpenID. La réponse inclut toutes les métadonnées dont votre client a besoin pour interagir avec ce locataire.
| Champ | Description |
|---|---|
| issuer | L'URL de l'émetteur du locataire |
| authorization_endpoint | URL pour les requêtes d'autorisation |
| token_endpoint | URL pour l'échange de jetons |
| userinfo_endpoint | URL pour récupérer les revendications utilisateur |
| jwks_uri | URL pour le JSON Web Key Set |
| revocation_endpoint | URL pour la révocation de jetons |
| introspection_endpoint | URL pour l'introspection de jetons |
| end_session_endpoint | URL pour la déconnexion / fin de session |
| device_authorization_endpoint | URL pour les requêtes d'autorisation d'appareil |
| pushed_authorization_request_endpoint | URL du point de terminaison Pushed Authorization Request (RFC 9126). |
| require_pushed_authorization_requests | Indique si le locataire exige globalement PAR. Même quand cela vaut false, des clients individuels peuvent toujours définir RequirePushedAuthorizationRequests = true. |
| scopes_supported | Liste des portées prises en charge |
| response_types_supported | Types de réponse pris en charge |
| grant_types_supported | Types de grants pris en charge |
| code_challenge_methods_supported | Méthodes PKCE prises en charge (S256) |
| backchannel_logout_supported | Indique si la déconnexion back-channel est prise en charge |
GET /.well-known/openid-configuration/jwks
Renvoie le JSON Web Key Set utilisé pour vérifier les signatures de jetons. La réponse contient un tableau keys de clés publiques EC P-256 (les jetons sont signés en ES256), chacune incluant les champs kty (EC), use, kid, alg, crv, x et y.
curl https://acme.authagonal.io/.well-known/openid-configuration
Point de terminaison d'autorisation
GET /connect/authorize
Initie un flux authorization code. L'utilisateur doit avoir une session active ou il sera redirigé vers la page de connexion. En cas de succès, l'utilisateur est redirigé vers votre application avec un code d'autorisation.
| Paramètre | Requis | Description |
|---|---|---|
response_type | Oui | Doit être "code" |
client_id | Oui | Votre identifiant client enregistré |
redirect_uri | Oui | Doit correspondre exactement a une URI de redirection enregistrée |
scope | Oui | Liste de portées séparées par des espaces (par ex. "openid profile email") |
state | Recommandé | Valeur opaque pour la protection CSRF, renvoyee inchangee dans la redirection |
code_challenge | Requis si PKCE | Hash SHA-256 encode en base64url du code_verifier |
code_challenge_method | Requis si PKCE | Doit être "S256" |
nonce | Optionnel | Valeur liée au jeton ID pour la protection contre la répétition |
login_hint | Optionnel | Pré-remplir le champ e-mail sur la page de connexion |
Réponse de succès : Redirection 302 vers redirect_uri avec les paramètres de requête code et state.
Réponse d'erreur : Redirection 302 avec les paramètres de requête error, error_description et state.
PKCE requis
code_verifier (une chaîne aléatoire de 43 caractères ou plus), hachez-le avec SHA-256 et encodez le résultat en base64url pour créer le code_challenge.Pushed Authorization Requests (PAR)
RFC 9126. Au lieu de placer chaque paramètre d'autorisation dans l'URL, votre client les envoie par POST à /connect/par avec une authentification client classique et reçoit en retour une request_uri opaque et de courte durée. Le navigateur visite ensuite /connect/authorize?client_id=...&request_uri=... — rien d'autre n'apparaît dans l'historique du navigateur, les logs du serveur ou les en-têtes Referer, et le serveur a déjà vérifié l'intégrité des paramètres sous authentification du client.
POST /connect/par
L'authentification client est la même que pour /connect/token : HTTP Basic avec client_id/client_secret, ou identifiants encodés dans le formulaire. Les clients publics publient sans secret. Le corps porte les mêmes paramètres que vous enverriez normalement à /connect/authorize ; request_uri lui-même est rejeté (chaîner un PAR est interdit par §2.1 de la spec). Renvoie 201 Created.
| Paramètre | Requis | Description |
|---|---|---|
client_id | Oui | Votre ID client. Doit correspondre au client authentifié. |
client_secret | Clients confidentiels | Votre secret client. Requis pour les clients confidentiels. |
response_type | Oui | Doit être "code" |
redirect_uri | Oui | Doit correspondre exactement a une URI de redirection enregistrée |
scope | Oui | Liste de portées séparées par des espaces (par ex. "openid profile email") |
code_challenge | Requis si PKCE | Hash SHA-256 encode en base64url du code_verifier |
code_challenge_method | Requis si PKCE | Doit être "S256" |
state | Recommandé | Valeur opaque pour la protection CSRF, renvoyee inchangee dans la redirection |
nonce | Optionnel | Valeur liée au jeton ID pour la protection contre la répétition |
Réponse
| Champ | Description |
|---|---|
request_uri | Référence opaque à usage unique, p. ex. <code>urn:ietf:params:oauth:request_uri:abc123…</code>. Passez-la à <code>/connect/authorize</code> en tant que <code>request_uri</code>. |
expires_in | Durée de vie de la <code>request_uri</code> en secondes. Par défaut 90 — valeur typique des IdP de référence. |
Sur l'appel suivant GET /connect/authorize?client_id=…&request_uri=…, tous les autres paramètres sont extraits de la charge utile poussée et tout paramètre de requête supplémentaire est ignoré. Le client_id de l'appel d'autorisation doit correspondre au client qui a poussé la requête. Une fois consommée (ou une fois expires_in écoulé), la request_uri est retirée du stockage.
Forcer PAR par client
/connect/authorize de sa part. La posture recommandée pour les clients à haut risque combine RequirePushedAuthorizationRequests = true avec PKCE, ce qui élimine totalement la barre d'URL en tant que surface d'attaque.# 1. Push parameters (server returns request_uri + expires_in) curl -X POST https://acme.authagonal.io/connect/par \ -u "my-app:CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "response_type=code" \ -d "redirect_uri=https://app.example.com/callback" \ -d "scope=openid profile email" \ -d "state=$(openssl rand -hex 16)" \ -d "code_challenge=YOUR_CODE_CHALLENGE" \ -d "code_challenge_method=S256" # 2. Send the user to /authorize with only client_id + request_uri # https://acme.authagonal.io/connect/authorize?client_id=my-app&request_uri=urn:ietf:params:oauth:request_uri:abc123...
Point de terminaison de jeton
POST /connect/token
Échange des identifiants contre des jetons. Les requêtes doivent utiliser Content-Type: application/x-www-form-urlencoded. L'authentification client peut être fournie via HTTP Basic auth (Authorization: Basic base64(client_id:client_secret)) ou comme paramètres dans le corps du formulaire (client_id + client_secret).
Grant Authorization Code
| Paramètre | Requis | Description |
|---|---|---|
grant_type | Oui | "authorization_code" |
code | Oui | Le code d'autorisation provenant de la redirection |
redirect_uri | Oui | Doit correspondre à l'URI utilisée dans la requête d'autorisation |
code_verifier | Requis si PKCE | La chaîne aléatoire originale utilisée pour générer le code_challenge |
client_id | Oui | Votre identifiant client (si vous n'utilisez pas Basic auth) |
client_secret | Clients confidentiels | Votre secret client (si vous n'utilisez pas Basic auth) |
Grant Refresh Token
| Paramètre | Requis | Description |
|---|---|---|
grant_type | Oui | "refresh_token" |
refresh_token | Oui | Le jeton de rafraîchissement à échanger |
client_id | Oui | Votre identifiant client |
client_secret | Clients confidentiels | Votre secret client |
Grant Client Credentials
| Paramètre | Requis | Description |
|---|---|---|
grant_type | Oui | "client_credentials" |
client_id | Oui | Votre identifiant client |
client_secret | Oui | Votre secret client |
scope | Optionnel | Portées séparées par des espaces à demander |
Grant Device Code
| Paramètre | Requis | Description |
|---|---|---|
grant_type | Oui | "urn:ietf:params:oauth:grant-type:device_code" |
device_code | Oui | Le code d'appareil provenant de la réponse d'autorisation d'appareil |
client_id | Oui | Votre identifiant client |
client_secret | Clients confidentiels | Votre secret client |
Réponse de jeton :
| Champ | Description |
|---|---|
access_token | Le jeton d'accès pour les appels API |
token_type | "Bearer" |
expires_in | Durée de vie du jeton en secondes |
id_token | Jeton ID OpenID Connect (lorsque la portée openid est demandée) |
refresh_token | Jeton de rafraîchissement (lorsque la portée offline_access est accordée) |
curl -X POST https://acme.authagonal.io/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=AUTHORIZATION_CODE" \ -d "redirect_uri=https://app.example.com/callback" \ -d "client_id=my-app" \ -d "code_verifier=YOUR_CODE_VERIFIER"
Point de terminaison UserInfo
GET /connect/userinfo
Renvoie les revendications concernant l'utilisateur authentifié. Nécessite un jeton d'accès valide avec la portée openid.
| Champ | Type | Description |
|---|---|---|
sub | string | Identifiant unique de l'utilisateur |
email | string | Adresse e-mail de l'utilisateur |
email_verified | boolean | Indique si l'e-mail a été vérifié |
given_name | string | Prénom |
family_name | string | Nom de famille |
name | string | Nom d'affichage complet |
phone_number | string | Numéro de téléphone (si fourni). Délivré avec la portée <code>phone</code>. |
org_id | string | L'organisation à laquelle appartient l'utilisateur. Attribuée par votre propre application de provisionnement (voir Applications de provisionnement) ou définie avec PUT /api/v1/users/{userId} ; Authagonal ne la dérive jamais. Publiée sous le scope profile, et absente lorsque l'utilisateur n'en a pas. |
roles | string[] | Tableau des rôles assignés. Délivré uniquement lorsque le jeton porte la portée <code>roles</code>. |
groups | object[] | Tableau des appartenances aux groupes, chacune avec id et name. Délivré uniquement lorsque le jeton porte la portée <code>groups</code>. |
curl https://acme.authagonal.io/connect/userinfo \ -H "Authorization: Bearer ACCESS_TOKEN"
Introspection de jeton (RFC 7662)
POST /connect/introspect
Valide un jeton et renvoie ses métadonnées. Nécessite des identifiants client (Basic auth ou paramètres dans le corps du formulaire).
| Paramètre | Requis | Description |
|---|---|---|
token | Oui | Le jeton à introspecter |
token_type_hint | Optionnel | Indication sur le type de jeton (par ex. "refresh_token") |
Réponse de jeton actif :
| Champ | Description |
|---|---|
active | true |
sub | Sujet (identifiant utilisateur) |
client_id | Client auquel le jeton a été émis |
scope | Portées accordées séparées par des espaces |
iss | Émetteur |
exp | Date d'expiration (timestamp Unix) |
iat | Date d'émission (timestamp Unix) |
aud | Audience |
token_type | Type de jeton (par ex. "Bearer") |
Réponse de jeton inactif : { "active": false }
Toujours 200 OK
active: false. La seule exception concerne l'appelant lui-même : un client dont l'authentification échoue reçoit 401 invalid_client.curl -X POST https://acme.authagonal.io/connect/introspect \ -u "my-app:CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "token=ACCESS_OR_REFRESH_TOKEN"
Révocation de jeton (RFC 7009)
POST /connect/revocation
Révoqué un jeton précédemment émis. Nécessite des identifiants client.
| Paramètre | Requis | Description |
|---|---|---|
token | Oui | Le jeton à révoquer |
token_type_hint | Optionnel | Indication sur le type de jeton (par ex. "refresh_token") |
Le point de terminaison renvoie toujours 200 OK, même pour les jetons invalides ou déjà révoqués, conformément a la spécification RFC 7009.
Jetons d'accès et de rafraîchissement
Autorisation d'appareil (RFC 8628)
POST /connect/deviceauthorization
Initie le flux d'autorisation d'appareil pour les appareils à saisie limitee (CLI, smart TV, appareils IoT). L'appareil affiche un code à l'utilisateur, qui approuve ensuite la requête sur un appareil séparé disposant d'un navigateur.
| Paramètre | Requis | Description |
|---|---|---|
client_id | Oui | Votre identifiant client |
client_secret | Clients confidentiels | Votre secret client |
scope | Optionnel | Portées séparées par des espaces (par défaut "openid") |
Réponse :
| Champ | Description |
|---|---|
device_code | Code de vérification d'appareil (utilise pour le polling) |
user_code | Code affiché à l'utilisateur au format XXXX-XXXX |
verification_uri | URL que l'utilisateur visite pour entrer le code |
verification_uri_complete | URL avec le user_code pré-rempli |
expires_in | 300 par défaut (en secondes, le code est donc valide pendant 5 minutes). Défini par client. |
interval | 5 (secondes — intervalle minimum de polling) |
Flux d'approbation : L'utilisateur visite la verification_uri, entre le user_code et approuve la requête. Pendant ce temps, l'appareil interroge le point de terminaison de jeton avec le device_code.
Codes d'erreur de polling :
| Erreur | Signification |
|---|---|
authorization_pending | L'utilisateur n'a pas encore approuvé — continuez le polling |
expired_token | Le code d'appareil à expire — relancez le flux |
access_denied | L'utilisateur a refusé la requête d'autorisation |
curl -X POST https://acme.authagonal.io/connect/deviceauthorization \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=my-cli" \ -d "scope=openid profile email"
Fin de session / Déconnexion
GET POST /connect/endsession
Déconnecte la session utilisateur actuelle, notifie chaque client ayant une URI de déconnexion back-channel ou front-channel enregistrée, et révoque les grants liés à cette session. Sans id_token_hint correspondant à la session actuelle, l'utilisateur doit d'abord confirmer la déconnexion.
| Paramètre | Requis | Description |
|---|---|---|
id_token_hint | Optionnel | Le jeton ID — utilise pour valider le post_logout_redirect_uri |
post_logout_redirect_uri | Optionnel | Ou rediriger après la déconnexion (doit être enregistré) |
state | Optionnel | Valeur opaque renvoyee dans la redirection |
Si un post_logout_redirect_uri valide est fourni et correspond a une URI enregistrée, l'utilisateur reçoit une redirection 302. Sinon, une réponse JSON confirme que la session a été terminée.
Déconnexion back-channel
BackChannelLogoutUri de chaque client. Le JWT contient sub, aud, iss et la revendication d'événement http://schemas.openid.net/event/backchannel-logout. Votre application doit invalider la session locale de l'utilisateur lorsqu'elle reçoit cette notification.Référence API SCIM 2.0
Authagonal prend en charge le protocole SCIM 2.0 pour le provisionnement automatisé des utilisateurs et des groupes. Les fournisseurs d'identité tels qu'Okta, Azure AD et OneLogin peuvent utiliser cette API pour maintenir votre locataire Authagonal synchronisé avec votre annuaire d'entreprise.
URL de base : https://{slug}.authagonal.io/scim/v2
Authentification : Toutes les requêtes nécessitent un jeton Bearer. Générez un jeton SCIM dans le portail sur la page SCIM : sélectionnez le client pour lequel votre IdP provisionne, puis Créer un jeton.
En-têtes communs :
| En-tête | Valeur |
|---|---|
Authorization | Bearer SCIM_TOKEN |
Content-Type | application/scim+json |
Les points de terminaison de liste acceptent count (100 par défaut, 200 max ; 0 ne renvoie que le total) et le filtrage via le paramètre filter (par ex. userName eq "[email protected]"). Les utilisateurs se paginent avec cursor : passez le nextCursor de la réponse précédente. Les groupes acceptent soit startIndex (base 1), soit cursor.
Utilisateurs
GET /scim/v2/Users: Lister les utilisateurs avec pagination et filtrage optionnels.
| Paramètre de requête | Description |
|---|---|
startIndex | Seule la valeur 1 est acceptée pour les utilisateurs ; paginez plutôt avec cursor. Une valeur supérieure renvoie 400 invalidValue. |
cursor | Curseur de pagination opaque : passez le nextCursor de la page précédente pour obtenir la page suivante |
count | Nombre maximum de résultats par page (par défaut : 100, max : 200 ; 0 ne renvoie que le total) |
filter | Expression de filtre SCIM (par ex. userName eq "[email protected]") |
GET /scim/v2/Users/{id}: Obtenir un utilisateur unique par son identifiant utilisateur Authagonal.
POST /scim/v2/Users: Créer un nouvel utilisateur. Renvoie 201 Created.
| Champ | Requis | Description |
|---|---|---|
userName | Oui | Adresse e-mail (doit être unique au sein du locataire) |
name.givenName | Non | Prénom |
name.familyName | Non | Nom de famille |
displayName | Non | Nom d'affichage complet |
active | Non | Indique si l'utilisateur est actif (par défaut : true) |
externalId | Non | Identifiant provenant du fournisseur d'identité en amont |
PUT /scim/v2/Users/{id}: Remplacement complet d'une ressource utilisateur. Tous les champs doivent être fournis.
PATCH /scim/v2/Users/{id}: Mise à jour partielle utilisant SCIM PatchOp.
| Opération | Chemins pris en charge | Exemple de valeur |
|---|---|---|
replace | userName, active, name.givenName, name.familyName, displayName, externalId, preferredLanguage | true / false, ou une valeur de chaîne |
add | userName, active, name.givenName, name.familyName, displayName, externalId, preferredLanguage | true / false, ou une valeur de chaîne |
remove | name.givenName, name.familyName, displayName, externalId, preferredLanguage | (aucune valeur nécessaire) |
DELETE /scim/v2/Users/{id}: Supprime l'utilisateur de manière logique (désactivé le compte et révoqué tous les jetons). Renvoie 204 No Content.
curl -X POST https://acme.authagonal.io/scim/v2/Users \
-H "Authorization: Bearer SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "[email protected]",
"name": {
"givenName": "Jane",
"familyName": "Smith"
},
"displayName": "Jane Smith",
"active": true,
"externalId": "ext-12345"
}'Groupes
GET /scim/v2/Groups: Lister tous les groupes avec pagination et filtrage optionnels.
GET /scim/v2/Groups/{id}: Obtenir un groupe unique par ID, y compris sa liste de membres.
POST /scim/v2/Groups: Créer un nouveau groupe. Renvoie 201 Created.
| Champ | Requis | Description |
|---|---|---|
displayName | Oui | Nom d'affichage du groupe |
members | Non | Tableau d'objets membres, chacun avec un champ value contenant l'identifiant utilisateur |
externalId | Non | Identifiant provenant du fournisseur d'identité en amont |
PUT /scim/v2/Groups/{id}: Remplacement complet d'une ressource de groupe (y compris sa liste de membres).
PATCH /scim/v2/Groups/{id}: Mise à jour partielle : ajouter, supprimer ou remplacer des membres, ou modifier displayName et externalId.
DELETE /scim/v2/Groups/{id}: Supprime définitivement le groupe. Renvoie 204 No Content.
curl -X PATCH https://acme.authagonal.io/scim/v2/Groups/GROUP_ID \
-H "Authorization: Bearer SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "add",
"path": "members",
"value": [
{ "value": "USER_ID_1" },
{ "value": "USER_ID_2" }
]
}
]
}'Réponses d'erreur SCIM
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "400", "detail": "..." }. Les codes de statut courants incluent 400 (requête incorrecte), 404 (ressource introuvable), 409 (conflit / doublon) et 429 (limite de débit atteinte).API du portail (automatisation)
L'API du portail permet à votre propre backend d'automatiser tout ce que vous pouvez faire dans le portail — gérer les utilisateurs, les clients, les groupes, les rôles, les portées, les connexions SSO et les paramètres — à l'aide d'un identifiant machine à machine. Il s'agit de la même API que celle appelée par l'interface du portail.
URL de base : https://portal-api.<your-domain>/api/v1. Les requêtes s'authentifient avec un jeton d'accès Bearer ; le locataire est déterminé à partir du jeton, et non de l'URL.
Créer un identifiant d'API
Dans le portail, ouvrez Clients → Create API credential, choisissez un niveau d'accès et donnez-lui un nom. Authagonal génère un client OAuth client_credentials configuré pour l'API du portail et renvoie un ID client et un secret.
Copiez le secret immédiatement
Niveaux d'accès
| Portée | Accordé |
|---|---|
tenant:owner | Accès complet, y compris les actions destructrices réservées au propriétaire, telles que la suppression de l'ensemble du locataire. |
tenant:admin | Gérer tout, sauf les actions réservées au propriétaire — utilisateurs, clients, SSO, groupes, rôles, identité visuelle et paramètres. |
tenant:developer | Gérer les clients, les portées, l'identité visuelle et les applications de provisionnement. |
tenant:support | Lire et gérer les utilisateurs pour les tâches de support, et lire le journal d'audit. |
Vous ne pouvez accorder que ce que vous detenez
Obtenir un jeton
Échangez l'identifiant contre un jeton d'accès au point de terminaison de jeton de votre tenant administratif — https://<your-tenant>.<your-domain>/connect/token — puis envoyez le jeton dans un en-tête Bearer à l'API du portail. Les jetons sont valides pendant une heure.
# 1. Exchange the credential for an access token (your tenant's token endpoint)
curl -X POST https://acme.authagonal.io/connect/token \
-d grant_type=client_credentials \
-d client_id=api-3f2a... \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope=tenant:admin
# Response: { "access_token": "ey...", "token_type": "Bearer", "expires_in": 3600 }
# 2. Call the Portal API with the access token
curl https://portal-api.authagonal.io/api/v1/users \
-H "Authorization: Bearer $ACCESS_TOKEN"Points de terminaison
Tous les chemins sont relatifs à l'URL de base et nécessitent un jeton d'accès Bearer. La portée indiquée à côté de chaque groupe correspond au niveau d'accès minimal requis pour les identifiants. La pagination diffère selon la ressource : les utilisateurs et le journal d'audit acceptent count (1 à 200, 50 par défaut) et after, défini sur le continuationToken de la réponse précédente ; les groupes acceptent startIndex et count ; les organisations acceptent limit et cursor ; les clients, rôles et portées renvoient toutes les lignes.
tenant:developerGET/api/v1/clientsLister les clients OAuth.
GET/api/v1/clients/{id}Récupérer un client par son ID.
POST/api/v1/clientsCréer un client. Renvoie 201 avec l'enregistrement du client. Les secrets ne sont pas renvoyés ici : générez-en un avec POST /api/v1/clients/{clientId}/secrets, qui ne l'affiche qu'une seule fois.
PUT/api/v1/clients/{id}Mettre à jour un client (URI de redirection, types d'autorisation, durées de vie des jetons, exigences PKCE/PAR).
DELETE/api/v1/clients/{id}Supprimer un client.
POST/api/v1/clients/api-credentialGénérer un identifiant d'API Portal machine-to-machine.
tenant:supportGET/api/v1/usersLister les utilisateurs. Prend en charge count, search (préfixe d'e-mail ou de nom), organizationId pour filtrer sur une organisation, et after pour la pagination par curseur.
GET/api/v1/users/countNombre total d'utilisateurs du locataire.
GET/api/v1/users/stats/mfaStatistiques d'inscription à la MFA.
GET/api/v1/users/{id}Récupérer un utilisateur.
POST/api/v1/users/inviteInviter un utilisateur par e-mail. Crée un compte en attente et envoie par e-mail un lien permettant à l'invité de définir son propre mot de passe. Les champs optionnels organizationId et organizationRoles ajoutent également une appartenance à une organisation.
PUT/api/v1/users/{id}Mettre à jour un utilisateur (profil, email, isActive, emailConfirmed, organizationId). La modification de email ou de emailConfirmed nécessite tenant:admin.
DELETE/api/v1/users/{id}Supprimer un utilisateur.
GET/api/v1/users/{id}/mfaGet a user's enrolled MFA methods.
DELETE/api/v1/users/{id}/mfaReset a user's MFA enrollment. Needs tenant:admin.
tenant:adminGET/api/v1/rolesLister les rôles.
POST/api/v1/rolesCréer un rôle.
DELETE/api/v1/roles/{id}Supprimer un rôle.
POST/api/v1/roles/assignAttribuer un rôle à un utilisateur.
POST/api/v1/roles/unassignRetirer un rôle à un utilisateur.
tenant:adminGET/api/v1/groupsLister les groupes.
GET/api/v1/groups/{id}Récupérer un groupe et ses membres.
POST/api/v1/groupsCréer un groupe.
POST/api/v1/groups/{id}/membersAjouter des membres à un groupe.
DELETE/api/v1/groups/{groupId}/members/{userId}Retirer un membre d'un groupe.
DELETE/api/v1/groups/{id}Supprimer un groupe.
GET/api/v1/group-role-mappingsLister les correspondances groupe-rôle (rôles accordés à l'émission du jeton selon l'appartenance au groupe).
tenant:developerGET/api/v1/scopesLister les portées d'API.
POST/api/v1/scopesCréer une portée.
DELETE/api/v1/scopes/{name}Supprimer une portée.
tenant:adminGET/api/v1/saml/connectionsLister les connexions SAML.
POST/api/v1/saml/connectionsCréer une connexion SAML.
DELETE/api/v1/saml/connections/{id}Supprimer une connexion SAML.
GET/api/v1/oidc/connectionsLister les connexions OIDC.
POST/api/v1/oidc/connectionsCréer une connexion OIDC.
DELETE/api/v1/oidc/connections/{id}Supprimer une connexion OIDC.
GET/api/v1/sso/domainsLister les domaines routés vers les connexions SSO (découverte du domaine d'origine).
tenant:developerGET/api/v1/brandingRécupérer la personnalisation du locataire (couleurs, logo, langues prises en charge).
PUT/api/v1/brandingMettre à jour la personnalisation du locataire.
tenant:adminGET/api/v1/settingsRécupérer les paramètres du locataire (webhooks, inscription publique, politique de jetons).
PUT/api/v1/settingsMettre à jour les paramètres du locataire.
POST/api/v1/settings/webhook-secret/regenerateFaire pivoter le secret de signature des webhooks.
POST/api/v1/settings/test-emailEnvoyer un e-mail de test avec la configuration e-mail actuelle.
tenant:adminGET/api/v1/custom-domainsLister les domaines de connexion personnalisés et leur statut de vérification.
POST/api/v1/custom-domainsAjouter un domaine personnalisé.
POST/api/v1/custom-domains/{domain}/verifyDéclencher la vérification DNS d'un domaine personnalisé.
DELETE/api/v1/custom-domains/{domain}Supprimer un domaine personnalisé.
GET/api/v1/email/domains/{domainId}Obtenir les enregistrements DNS et le statut de vérification d'un domaine e-mail d'expéditeur.
tenant:supportGET/api/v1/auditInterroger le journal d'audit du locataire.
Provisionnement des utilisateurs via SCIM
Exemple : inviter un utilisateur
curl -X POST https://portal-api.authagonal.io/api/v1/users/invite \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"firstName": "Ada",
"lastName": "Lovelace"
}'
# 200 OK
# { "userId": "8f3a...", "email": "[email protected]" }Tout ce que l'interface peut faire
API Organisations
Toutes les routes ci-dessous exigent la politique TenantAdmin et se trouvent sous /api/v1/organizations, sauf indication contraire. Voir API du portail pour savoir comment obtenir un identifiant d'accès. Les deux routes de liste sont paginées par curseur : passez limit (50 par défaut, de 1 à 200) et le nextCursor précédent en tant que cursor ; elles répondent { items, nextCursor }, et un curseur invalide donne 400 invalid_cursor. L'objet organisation comporte une liste domains en lecture seule.
| Méthode | Chemin | Corps | Notes |
|---|---|---|---|
| GET | /api/v1/organizations | – | Une page d'organisations, par ordre d'identifiant. Requête : cursor?, limit? (50 par défaut, de 1 à 200). Renvoie { items, nextCursor } ; un nextCursor nul indique la dernière page. |
| POST | /api/v1/organizations | slug, name, brandingJson?, enabled?, requireMembershipForTokens?, allowAutoMembership?, metadata? | 201 + l'organisation. 409 slug_taken. |
| GET | /api/v1/organizations/{idOrSlug} | – | Recherchée d'abord par identifiant, puis par slug. |
| PUT | /api/v1/organizations/{id} | name?, brandingJson?, slug?, enabled?, requireMembershipForTokens?, allowAutoMembership?, metadata? | Seuls les champs nommés changent. Un slug différent est refusé : il est immuable une fois créé. domains ne peut pas être modifié ici. |
| DELETE | /api/v1/organizations/{id} | – | Supprime d'abord toutes les appartenances de l'organisation, puis l'organisation elle-même. |
| GET | /api/v1/organizations/{id}/members | – | Une page d'appartenances par ordre d'identifiant d'utilisateur, avec l'e-mail et le nom à jour du membre résolus depuis le magasin d'utilisateurs. Requête : cursor?, limit?. |
| POST | /api/v1/organizations/{id}/members | userId? | email?, status?, roles? | 201 + l'appartenance. 404 user_not_found. 409 membership_exists. Les rôles réservés tenant:* et platform:* sont refusés avec 400 invalid_role, pas retirés silencieusement. |
| PUT | /api/v1/organizations/{id}/members/{userId} | status?, roles? | Passer le statut à active renseigne joinedAt s'il ne l'était pas déjà. |
| DELETE | /api/v1/organizations/{id}/members/{userId} | – | Supprime la ligne définitivement, ce n'est pas un changement de statut. |
| POST | /api/v1/organizations/{id}/domains | domain | Revendique un domaine de messagerie, non vérifié. 201 + { domain, verified, verifiedAt, createdAt, recordName, recordValue }. 400 domain_invalid. 409 domain_exists, domain_taken. |
| POST | /api/v1/organizations/{id}/domains/{domain}/verify | – | Recherche l'enregistrement TXT à recordName et compare recordValue exactement. 200 + le domaine lorsqu'il est vérifié (une répétition est un 200 sans effet) ; 409 verification_failed en cas d'échec ; 409 domain_taken ; 404 domain_not_found. |
| DELETE | /api/v1/organizations/{id}/domains/{domain} | – | 204. Abandonne la revendication, vérifiée ou non. Les membres existants sont conservés. 404 domain_not_found. |
| POST | /api/v1/organizations/backfill | dryRun? = true | Migre l'ancienne étiquette AuthUser.organizationId vers de vraies lignes Organization/OrganizationMembership. |
| GET | /api/v1/users/{userId}/organizations | – | Toutes les organisations auxquelles cet utilisateur appartient, avec son statut et ses rôles dans chacune. |
Écrans de connexion
Voici les écrans hébergés que vos utilisateurs finaux voient sur le serveur d'authentification de votre tenant. Authagonal livre chaque écran prêt à l'emploi, vous obtenez donc une expérience de connexion complète et sécurisée sans construire la moindre interface. Cette page passe en revue chaque écran et montre quels paramètres du portail le contrôlent.
Entièrement en marque blanche
prefers-color-scheme, ils basculent donc entre clair et sombre selon l'appareil de l'utilisateur.Connexion


- Flux en deux étapes, e-mail d'abord : l'utilisateur saisit son e-mail et clique sur Continuer, puis le champ du mot de passe apparaît.
- Les boutons d'authentification unique « Continuer avec {provider} » apparaissent automatiquement lorsque des connexions SSO existent.
- Les liens Mot de passe oublié et Créer un compte, chacun pouvant être affiché ou masqué.
- Captcha Cloudflare Turnstile optionnel pour dissuader les tentatives de connexion automatisées.
Contrôlé depuis l'administration du portail
- La Personnalisation de marque définit le logo, la couleur, le nom de l'application, l'e-mail de support et le CSS personnalisé.
- Affichez ou masquez les liens mot de passe oublié et inscription (Personnalisation de marque).
- Les connexions SSO ajoutent les boutons de connexion sociale (page SSO).
- Durée de vie des sessions et seuils de verrouillage (Paramètres → Session).
Inscription


- Collecte le prénom et le nom (optionnels), l'e-mail et un mot de passe.
- Une liste de contrôle de la politique de mot de passe en direct se met à jour à mesure que l'utilisateur saisit, pour que les exigences soient claires avant validation.
- Captcha Cloudflare Turnstile optionnel.
- Un lien « Se connecter » pour les utilisateurs qui ont déjà un compte.
Contrôlé depuis l'administration du portail
- Affichez ou masquez le lien inscription (Identité visuelle). Pour désactiver entièrement l'inscription, désactivez Autoriser l'inscription publique (Paramètres → Session).
- La politique de mot de passe de votre tenant pilote la liste de contrôle.
- La Personnalisation de marque stylise tout l'écran.
Mot de passe oublié


- L'utilisateur saisit son e-mail, puis voit une confirmation neutre « vérifiez votre e-mail ».
- L'écran ne révèle jamais si un compte existe, ce qui déjoue le sondage par énumération de comptes.
- Un lien « Retour à la connexion » ramène l'utilisateur à l'écran de connexion.
Contrôlé depuis l'administration du portail
- Affichez ou masquez le lien mot de passe oublié (Personnalisation de marque).
- La distribution d'e-mails de votre tenant envoie le message de réinitialisation.
- La Personnalisation de marque stylise tout l'écran.
Réinitialiser le mot de passe


- Champs nouveau mot de passe et confirmer le mot de passe avec une liste de contrôle des exigences en direct, règle par règle.
- Un état clair lien invalide ou expiré lorsque le jeton de réinitialisation n'est plus valide.
- Un état de succès confirmant que le mot de passe a été changé.
Contrôlé depuis l'administration du portail
- La politique de mot de passe de votre tenant pilote la liste de contrôle.
- La Personnalisation de marque stylise tout l'écran.
Défi MFA


- Un sélecteur de méthode entre application d'authentification, passkey et code de récupération.
- Un champ TOTP à 6 chiffres qui se valide automatiquement une fois tous les chiffres saisis.
- La saisie d'un code de récupération pour les utilisateurs qui ont perdu l'accès à leur application d'authentification.
- Un bouton passkey pour une vérification matérielle.
Contrôlé depuis l'administration du portail
- La politique MFA se définit par application (Clients → Sécurité).
- Tout utilisateur disposant d'un facteur enregistré est toujours soumis au défi, quelle que soit la politique.
Configuration MFA


- Affiche le statut des méthodes enregistrées pour que l'utilisateur sache ce qui est déjà configuré.
- Configuration de l'application d'authentification via QR code, avec une clé manuelle de secours et une étape de confirmation.
- Enregistrement d'un passkey pour une authentification matérielle.
- Génération de codes de récupération pour la récupération de compte.
- Une option ignorer facultative lorsque la MFA est en libre-service plutôt qu'obligatoire.
Contrôlé depuis l'administration du portail
- La politique MFA se définit par application ; Obligatoire force la configuration à la connexion (Clients → Sécurité).
- La Personnalisation de marque stylise tout l'écran.
Autorisation d'appareil


- Un champ de saisie du code utilisateur centré pour le code affiché sur l'appareil.
- Une étape d'approbation pour autoriser l'appareil.
- Un écran intermédiaire de connexion lorsque l'utilisateur n'est pas encore authentifié.
- Une confirmation d'approbation une fois l'appareil autorisé.
Contrôlé depuis l'administration du portail
- Activez le grant de code d'appareil sur l'application (Clients → Scopes & Grants).
- Définissez la durée de vie du code d'appareil (Clients → Jetons).
Consentement


- Affiche le logo et le nom du client demandeur.
- Une liste par scope avec des libellés clairs et lisibles pour chaque permission.
- Des boutons Autoriser et Refuser pour accorder ou refuser l'accès.
- Un pied de page d'indication de consentement expliquant ce que la décision implique.
Contrôlé depuis l'administration du portail
- Activez Exiger le consentement par application (Clients → Général).
- Le logo, le nom et l'URL proviennent des propres métadonnées de l'application.
- La Personnalisation de marque habille la carte de consentement.
Applications connectées (grants)


- Liste toutes les applications que l'utilisateur a autorisées, avec leur nom, leurs portées et la date d'autorisation.
- Révoquez l'accès à une application, avec une étape de confirmation avant que cela prenne effet.
- Un état vide convivial lorsque l'utilisateur n'a autorisé aucune application.
Contrôlé depuis l'administration du portail
- La liste est alimentée par les applications nécessitant un consentement.
- La Personnalisation de marque stylise tout l'écran.
Compte
Une page de compte en libre-service hébergée sur /login/account où les utilisateurs connectés gèrent leur propre profil et leur langue préférée, sans accès au portail.


- Modifier les prénom et nom, l'entreprise et le téléphone ; l'adresse e-mail est affichée en lecture seule.
- Choisir une langue préférée parmi les langues prises en charge ; l'interface prévisualise le choix instantanément et le conserve à l'enregistrement.
- La langue enregistrée pilote l'interface hébergée de l'utilisateur et la langue des e-mails transactionnels qu'il reçoit.
Contrôlé depuis l'administration du portail
- Branding habille tout l'écran.
- La même langue préférée est modifiable par un administrateur depuis la page Utilisateurs du portail.
Flux d'authentification
Les flux d'authentification couvrent la manière dont les utilisateurs finaux interagissent avec votre locataire Authagonal — connexion, inscription, réinitialisation de mot de passe et configuration de la MFA. Ces points de terminaison sont utilisés par la page de connexion hébergée et peuvent être appelés directement si vous construisez une interface de connexion personnalisée.
Connexion
POST /api/auth/login
Authentifié un utilisateur avec un e-mail et un mot de passe. En cas de succès, signe un cookie de session et renvoie le profil utilisateur. Si la MFA est configurée, la réponse indique qu'un second facteur est requis avant que la session ne soit complètement établie.
Corps de la requête :
{
"email": "[email protected]",
"password": "correct-horse-battery-staple"
}Réponse de succès :
| Champ | Type | Description |
|---|---|---|
userId | string | Identifiant unique de l'utilisateur |
email | string | Adresse e-mail de l'utilisateur |
name | string | Nom d'affichage complet |
mfaAvailable | boolean | Indique si l'utilisateur a des méthodes MFA inscrites |
Réponse MFA requise : Lorsque l'utilisateur a la MFA inscrite, la réponse inclut mfaRequired: true ainsi qu'un challengeId et un tableau methods listant les méthodes MFA disponibles.
Réponse de configuration MFA requise : Lorsque la politique MFA de l'application est Obligatoire mais que l'utilisateur ne s'est pas encore inscrit, la réponse inclut mfaSetupRequired: true avec un setupToken pour le flux d'inscription.
Réponses d'erreur :
| Code d'erreur | Statut HTTP | Description |
|---|---|---|
invalid_credentials | 401 | L'e-mail ou le mot de passe est incorrect |
account_disabled | 403 | Le compte a été désactivé par un administrateur |
email_not_confirmed | 403 | L'utilisateur n'a pas vérifié son adresse e-mail |
locked_out | 423 | Le compte est temporairement verrouillé (inclut retryAfter en secondes). Renvoyé uniquement lorsque le mot de passe est correct ; un mot de passe erroné pendant le verrouillage renvoie invalid_credentials |
sso_required | 409 | Le domaine d'e-mail a le SSO configuré (inclut redirectUrl) |
too_many_attempts | 429 | Trop de tentatives de connexion depuis cette IP ou pour cet e-mail ; réessayez plus tard |
captcha_failed | 400 | Le défi Turnstile a échoué ou est absent (uniquement lorsque Turnstile est activé) |
Vérification SSO : Si le domaine d'e-mail de l'utilisateur a une connexion SSO configurée, le point de terminaison de connexion renvoie sso_required avec une redirectUrl. Le client doit rediriger l'utilisateur vers le fournisseur SSO.
Verrouillage de compte : Après maxFailedAttempts tentatives de connexion échouées consécutives, le compte est verrouillé pendant lockoutDurationMinutes. Les deux valeurs sont configurables dans les paramètres du locataire.
Page de connexion hébergée
Inscription
POST /api/auth/register
Crée un nouveau compte utilisateur et envoie un e-mail de vérification. Tant que <strong>Exiger un e-mail vérifié pour se connecter</strong> (Paramètres → Session) est activé, ce qui est le cas par défaut, l'utilisateur doit vérifier son e-mail avant de pouvoir se connecter.
Corps de la requête :
{
"email": "[email protected]",
"password": "a-strong-password-here",
"firstName": "Jane",
"lastName": "Smith"
}| Champ | Requis | Description |
|---|---|---|
email | Oui | Adresse e-mail (doit être unique) |
password | Oui | Doit respecter la politique de mot de passe du locataire |
firstName | Non | Prénom |
lastName | Non | Nom de famille |
Succès : 201 Created avec le userId du nouveau compte. S'inscrire avec un e-mail déjà utilise renvoie aussi 201 : nous ne révélons jamais si un e-mail existe (pour empêcher l'énumération de comptes) et prévenons plutôt le véritable titulaire du compte par e-mail.
Réponses d'erreur :
| Code d'erreur | Statut HTTP | Description |
|---|---|---|
weak_password | 400 | Le mot de passe ne respecte pas la politique de mot de passe du locataire |
rate_limited | 429 | Trop de tentatives d'inscription |
provisioning_rejected | 422 | Un webhook de provisionnement a rejeté l'inscription |
invalid_email | 400 | L'adresse e-mail n'est pas valide |
captcha_failed | 400 | Le défi Turnstile a échoué ou est absent (uniquement lorsque Turnstile est activé) |
public_signup_disabled | 403 | L'inscription publique est désactivée pour ce locataire (Paramètres → Session) |
Politique de mot de passe
/api/auth/password-policy. Cela renvoie une liste rules : la longueur minimale et les classes de caractères requises.Réinitialisation du mot de passe
POST /api/auth/forgot-password
Demande un e-mail de réinitialisation de mot de passe. Le point de terminaison renvoie toujours une réponse de succès, que l'e-mail existe ou non, pour empêcher l'énumération des e-mails.
{
"email": "[email protected]"
}POST /api/auth/reset-password
Réinitialise le mot de passe de l'utilisateur en utilisant le jeton provenant du lien dans l'e-mail.
{
"token": "RESET_TOKEN_FROM_EMAIL",
"newPassword": "new-strong-password"
}Effets secondaires d'une réinitialisation de mot de passe réussie :
- Le compteur de tentatives de connexion échouées est remis à zéro
- Tous les jetons de rafraîchissement existants sont révoqués
- Un nouveau tampon de sécurité est généré (invalidant toutes les sessions existantes)
Configuration et vérification MFA
Authagonal prend en charge trois méthodes MFA : TOTP (applications d'authentification), WebAuthn (clés de sécurité et biométrie) et codes de récupération à usage unique.
Configuration TOTP
POST /api/auth/mfa/totp/setup: Renvoie un <code>setupToken</code>, un URI de données de QR code et une clé de saisie manuelle. L'utilisateur scanne le QR code avec son application d'authentification (Google Authenticator, Authy, 1Password, etc.), puis confirme l'inscription.
POST /api/auth/mfa/totp/confirm: Confirme l'inscription TOTP en envoyant le <code>setupToken</code> obtenu lors de la configuration avec un code à 6 chiffres provenant de l'application d'authentification.
{
"setupToken": "SETUP_TOKEN_FROM_SETUP_RESPONSE",
"code": "123456"
}Configuration WebAuthn
POST /api/auth/mfa/webauthn/setup — Renvoie les options de création d'identifiants pour l'API WebAuthn. Le navigateur appelle navigator.credentials.create() avec ces options.
POST /api/auth/mfa/webauthn/confirm: Confirme l'inscription WebAuthn en soumettant la réponse d'attestation du navigateur.
Codes de récupération
POST /api/auth/mfa/recovery/generate: Génère 10 codes de récupération à usage unique de 10 caractères (format <code>XXXXX-XXXXX</code>). Chaque code peut être utilisé exactement une fois pour contourner la MFA. Une application d'authentification ou une passkey doit d'abord être inscrite.
Les codes de récupération ne sont affichés qu'une seule fois
Vérification MFA
POST /api/auth/mfa/verify: Complète le défi MFA après une connexion par mot de passe réussie.
| Champ | Requis | Description |
|---|---|---|
challengeId | Oui | L'identifiant de défi provenant de la réponse de connexion |
method | Oui | "totp", "recovery" ou "webauthn" |
code | TOTP / Récupération | Code TOTP à 6 chiffres ou code de récupération (XXXXX-XXXXX) |
assertion | WebAuthn | La réponse d'assertion provenant de navigator.credentials.get() |
Statut MFA
GET /api/auth/mfa/status: Renvoie les méthodes MFA actuellement inscrites de l'utilisateur.
Flux de connexion SSO
Authagonal prend en charge les connexions SSO basées sur SAML 2.0 et OIDC. Le routage par domaine detecte automatiquement quel fournisseur SSO utiliser en fonction de l'adresse e-mail de l'utilisateur.
Vérification SSO
GET /api/auth/[email protected]
| Champ | Type | Description |
|---|---|---|
ssoRequired | boolean | Indique si le domaine d'e-mail requiert le SSO |
providerType | string | "saml" ou "oidc" |
connectionId | string | L'identifiant de la connexion SSO |
redirectUrl | string | L'URL vers laquelle rediriger l'utilisateur pour la connexion SSO |
Flux SAML
L'utilisateur est redirigé vers GET /saml/{connectionId}/login qui envoie une SAML AuthnRequest au fournisseur d'identité. L'IdP authentifié l'utilisateur et renvoie une réponse SAML au point de terminaison Assertion Consumer Service (ACS). Authagonal valide l'assertion, crée ou met à jour l'utilisateur et signe un cookie de session.
Les métadonnées SAML pour configurer votre IdP sont disponibles à GET /saml/{connectionId}/metadata.
Flux OIDC
L'utilisateur est redirigé vers GET /oidc/{connectionId}/login qui redirige vers le fournisseur d'identité en amont avec PKCE. Après l'authentification de l'utilisateur, le callback a /oidc/callback échange le code d'autorisation, valide le jeton ID et crée ou met à jour l'utilisateur.
Provisionnement JIT : Les flux SAML et OIDC prennent en charge le provisionnement just-in-time, désactivé par défaut sur chaque connexion (Activer le provisionnement JIT). Lorsqu'il est activé et que l'utilisateur n'existe pas encore dans le locataire, il est créé automatiquement à partir des revendications du fournisseur d'identité. S'il existe déjà, ses attributs de profil sont mis à jour pour correspondre aux dernières valeurs du fournisseur.
Routage par domaine
Backend-for-Frontend (BFF)
Un BFF garde les jetons OAuth entièrement hors du navigateur. Votre application monopage ne détient rien d'autre qu'un cookie de session httpOnly, et un client confidentiel sur votre propre backend exécute le flux OpenID Connect et conserve les jetons côté serveur.
Tout ce qu'une application monopage peut lire, une attaque de type cross-site scripting peut le voler, y compris un jeton d'accès en mémoire et un jeton de rafraîchissement dans localStorage. Stocker les jetons dans le navigateur plafonne aussi leur durée de vie, car un jeton de rafraîchissement de longue durée à portée des scripts est un risque permanent. La bonne pratique actuelle de l'IETF OAuth 2.0 for Browser-Based Apps recommande ce modèle précisément pour cette raison.
En échange, vous obtenez une session qui survit à un rechargement de page sans qu'aucun jeton n'apparaisse, le rafraîchissement pris en charge pour vous côté serveur, une révocation immédiate par la déconnexion back-channel, et un proxy authentifié pour que votre API n'ait jamais à analyser un jeton que le navigateur aurait pu altérer.
Créer le client
Dans le portail, ouvrez Clients et choisissez Créer une app BFF. Indiquez l'URL de base depuis laquelle votre application est servie, par exemple https://app.acme.com, et Authagonal enregistre pour vous un client confidentiel correctement configuré au lieu de vous laisser l'assembler :
| Paramètre | Valeur |
|---|---|
| URI de redirection | {appBaseUrl}/bff/callback |
| URI de redirection après déconnexion | {appBaseUrl}/ |
| URI de déconnexion back-channel | {appBaseUrl}/bff/backchannel-logout |
| Types de grants | authorization_code, refresh_token |
| Portées | openid, profile, email, offline_access |
| PKCE et secret client | Les deux sont requis |
Le secret n'est affiché qu'une seule fois
clientId, clientSecret et authority, et le secret n'est plus récupérable ensuite, car seul son hachage est conservé. Placez-le directement dans la configuration ou le coffre à secrets de votre backend. Si vous le perdez, créez un autre client plutôt que d'essayer de récupérer celui-ci.Le brancher dans votre backend
Deux runtimes sont pris en charge et partagent le même protocole de base : Authagonal.Bff pour .NET et @authagonal/bff pour Node, ce dernier avec des adaptateurs pour Express et Next.js. Pointez l'un ou l'autre vers les valeurs que le portail vient de vous donner. Le paquet Node nécessite aussi un cookieSecret qui vous est propre, qu'il utilise pour chiffrer ses cookies.
// dotnet add package Authagonal.Bff
builder.Services.AddAuthagonalBff(o =>
{
o.Authority = "https://acme.authagonal.io"; // your tenant auth host
o.ClientId = builder.Configuration["Bff:ClientId"]!;
o.ClientSecret = builder.Configuration["Bff:ClientSecret"]!;
o.Scope = ["openid", "profile", "email", "offline_access"];
o.PostLogoutRedirectUri = "https://app.acme.com/";
});
// Trust X-Forwarded-Proto from your ingress. With no options, UseForwardedHeaders() changes nothing.
builder.Services.Configure<ForwardedHeadersOptions>(o =>
{
o.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
o.KnownNetworks.Clear();
o.KnownProxies.Clear();
});
var app = builder.Build();
app.UseForwardedHeaders(); // required behind a proxy or ingress, see the note below
app.MapAuthagonalBff();
app.MapFallbackToFile("index.html"); // your SPA
app.Run();// npm install @authagonal/bff
import express from 'express';
import { authagonalBff } from '@authagonal/bff/express';
const app = express();
app.use(authagonalBff({
authority: 'https://acme.authagonal.io',
clientId: process.env.BFF_CLIENT_ID,
clientSecret: process.env.BFF_CLIENT_SECRET,
cookieSecret: process.env.BFF_COOKIE_SECRET, // encrypts the session and login cookies
scope: ['openid', 'profile', 'email', 'offline_access'],
postLogoutRedirectUri: 'https://app.acme.com/',
}));
app.listen(8080);Derrière un proxy, faites confiance aux en-têtes transférés
__Host- sans l'attribut Secure, que les navigateurs rejettent alors en silence. Le symptôme est une connexion qui se termine proprement et une session qui n'apparaît jamais. En .NET, activez XForwardedProto dans ForwardedHeadersOptions et appelez app.UseForwardedHeaders() avant MapAuthagonalBff(), comme ci-dessus : l'appel sans configuration ne fait confiance à aucun en-tête. Les adaptateurs Node lisent eux-mêmes X-Forwarded-Proto et marquent toujours un cookie __Host- comme Secure ; activez le paramètre trust-proxy de votre framework pour que l'adresse client transmise à votre API soit la vraie.Points de terminaison
Montés sous /bff par défaut. Ils doivent être servis depuis la même origine que votre SPA, car le cookie de session est httpOnly et same-origin : placez-les derrière le même nom d'hôte plutôt que sur un domaine d'API distinct.
| Route | Objectif |
|---|---|
GET /bff/login?returnUrl=/ | Démarre la connexion et redirige vers Authagonal. Ramène ensuite l'utilisateur vers returnUrl. |
GET /bff/callback | L'URI de redirection OIDC. Gérée pour vous, vous ne l'écrivez jamais. |
GET /bff/user | Renvoie isAuthenticated, les revendications de la session et sessionExpiresAt. Exige l'en-tête anti-forgery. |
GET|POST /bff/logout | Met fin à la session localement et chez Authagonal. |
POST /bff/backchannel-logout | Reçoit les notifications de déconnexion d'Authagonal, pour qu'une déconnexion ailleurs mette aussi fin à cette session. |
Depuis le navigateur
Chaque requête qui n'est pas une navigation doit porter un en-tête anti-forgery statique. Il protège contre la falsification de requête inter-site, aux côtés de l'attribut SameSite du cookie : un envoi de formulaire cross-site ne peut pas définir d'en-tête personnalisé, donc une requête qui ne le porte pas est refusée.
const me = await fetch('/bff/user', {
headers: { 'X-Authagonal-Bff': '1' },
}).then(r => r.json());
if (!me.isAuthenticated) {
// Navigate, do not fetch: this is a redirect to your identity provider.
window.location.href = '/bff/login?returnUrl=' + encodeURIComponent(location.pathname);
}Connectez-vous et déconnectez-vous en naviguant, pas en faisant un fetch : location.href = '/bff/login'. Ces routes répondent par une redirection vers votre fournisseur d'identité, et une chaîne de redirections n'est pas quelque chose que fetch peut suivre utilement.
Appeler votre API
Le BFF peut relayer votre API sous son propre chemin de base et y attacher au passage le jeton d'accès de la session. Le navigateur envoie un cookie, votre API reçoit un jeton bearer qu'elle valide normalement, et rien de ce jeton n'est visible ni falsifiable par la page. Déclarez une API en amont et les requêtes vers /bff/api/** l'atteignent authentifiées. Laissez la liste vide et le proxy est entièrement désactivé.
o.Upstreams.Add(new BffUpstream
{
Prefix = "/orders", // matches /bff/api/orders/**
TargetBaseUrl = "https://api.internal.acme.com",
StripPrefix = false, // keep /orders in the forwarded path
});| Option | Par défaut | Ce que cela fait |
|---|---|---|
Upstreams | [] | Les API vers lesquelles le proxy relaie. Vide, le point de terminaison du proxy est désactivé. |
Prefix | / | Préfixe de chemin après /bff/api que cette API en amont prend en charge, par exemple /orders. |
TargetBaseUrl | - | URL de base vers laquelle les requêtes sont relayées. |
StripPrefix | false | Retire le préfixe correspondant avant de relayer. Cela vous permet d'utiliser un préfixe de routage synthétique pour répartir un seul BFF vers plusieurs backends qui partagent un même espace de chemins. |
AllowAnonymousProxyRequests | false | Relaie une requête sans session exploitable sans en-tête Authorization, au lieu de la refuser. Pour une API qui sert à la fois des appelants connectés et anonymes. |
RequiredAuthority | [] | Un contrôle d'autorité sous forme de paires type:action, par exemple email:send. Lorsqu'il est défini, le proxy vérifie les authorization details RFC 9396 du jeton sortant avant de relayer. |
AuthorityLocation | - | La racine locations RFC 9396 sous laquelle cette API en amont est connue, lorsque l'autorité est accordée sur un identifiant de ressource public différent de l'adresse interne appelée par le proxy. |
StrictAuthority | false | Refuse un appel portant une contrainte de grant que le proxy ne peut pas évaluer, au lieu de le relayer. Le proxy relaie à l'aveugle et ne déduit aucun contexte de contrainte, ce paramètre est donc inactif par défaut. |
ExchangeRoutes | [] | Routes du proxy dont les appels en amont utilisent un jeton échangé lié à un contexte plutôt que le jeton d'accès principal de la session. Le premier motif correspondant l'emporte. |
WebSockets
Une poignée de main WebSocket ne peut porter ni en-tête personnalisé ni jeton bearer, donc ni l'en-tête anti-forgery ni le proxy n'aident. Activez les tickets et la SPA peut appeler GET /bff/ws-ticket, placer le ticket éphémère à usage unique sur l'URL de connexion, et laisser votre API le consommer. Générez-en un juste avant chaque connexion : il est supprimé à la première utilisation et expire en quelques secondes.
| Option | Par défaut | Ce que cela fait |
|---|---|---|
WsTicketsEnabled | false | Active le point de terminaison ws-ticket. Inactif par défaut. |
WsTicketLifetime | 30s | Durée de validité d'un ticket. Volontairement courte, puisqu'il circule dans une URL. |
TicketExchangeParams | [] | Paramètres de requête qu'une demande de ticket peut transmettre à un échange de jetons, pour que le ticket soit lié à ce contexte au lieu d'être valable pour tout. |
Remettre délibérément un jeton au navigateur
Tout l'intérêt d'un BFF est que le navigateur ne détient aucun jeton, ce mécanisme est donc facultatif et étroit. Il existe pour le seul cas que le modèle par cookie ne peut pas couvrir : un serveur de ressources sur une autre origine, par exemple une application que vous intégrez dans une iframe, qui doit être appelée avec un bearer. Une fois activé, GET /bff/token?resource=… renvoie un jeton échangé : le jeton de la session, restreint à une seule ressource autorisée et lié à un éventuel paramètre de contexte autorisé. Le navigateur ne voit jamais le jeton propre à la session, et ce qu'il obtient est de courte durée et destiné à une seule audience. Une requête désignant une ressource hors de la liste d'autorisation est refusée, ce qui empêche d'en faire une fabrique de jetons à usage général.
| Option | Par défaut | Ce que cela fait |
|---|---|---|
TokenEndpointEnabled | false | Active le point de terminaison de jeton. Inactif par défaut. |
TokenEndpointResources | [] | Les valeurs de resource auxquelles un jeton peut être destiné. Tout le reste est refusé. |
TokenEndpointExchangeParams | [] | Paramètres de requête transmis à l'échange comme liaisons de contexte, par exemple project_id. |
Servir plusieurs tenants depuis un seul BFF
Définissez un paramètre de requête de tenant et un seul déploiement sert plusieurs tenants : /bff/login?slug=acme sélectionne le tenant, un résolveur fournit l'autorité et les identifiants client de ce tenant, la clé voyage dans le cookie de corrélation jusqu'à la session, et la déconnexion back-channel résout le tenant à partir de l'émetteur du jeton. Le résolveur par défaut laisse le comportement mono-tenant identique au bit près, vous ne payez donc rien pour cette fonctionnalité tant que vous ne l'utilisez pas.
Exécuter plusieurs instances
Les sessions vivent derrière IBffSessionStore, dont l'implémentation par défaut est un cache en mémoire dans le processus. C'est très bien pour une seule instance et faux pour plusieurs : un utilisateur dont la requête suivante arrive sur un autre réplica est déconnecté. Enregistrez un magasin partagé, par exemple Redis via IDistributedCache, avant d'ajouter le BFF.
Un magasin partagé ne suffit pas à lui seul
ILeaseProvider via le clustering, ou implémentez IBffRefreshLockStore sur votre magasin de sessions, ce qui revient à une écriture conditionnelle avec une durée de vie et reste le chemin le plus court si vous exploitez déjà Redis. Un BFF dont le magasin semble partagé et qui n'a pas de verrou vous en avertit au démarrage, plutôt que de vous laisser le découvrir par un ticket de support.Options à connaître
L'ensemble complet, dans la graphie .NET. Le paquet Node prend les options de base en camelCase, ainsi BasePath devient basePath et SessionLifetime devient sessionLifetimeSeconds. PersistentCookie, CorrelationLifetime (fixé à 15 minutes en Node) et LoginPassthroughParams sont propres à .NET.
| Option | Par défaut | Ce que cela fait |
|---|---|---|
Authority | - | L'hôte d'authentification de votre tenant. Les métadonnées OIDC y sont découvertes. Requis sauf en multi-tenant, où le résolveur le fournit. |
ClientId | - | L'identifiant du client confidentiel enregistré pour ce BFF. |
ClientSecret | - | Le secret client. Un BFF est un client confidentiel, ce champ est donc requis. |
Scope | openid profile offline_access | Les portées demandées. Incluez offline_access, sinon il n'y a pas de jeton de rafraîchissement et les sessions se terminent en même temps que le jeton d'accès. |
BasePath | /bff | L'emplacement où les routes du BFF sont montées. |
CallbackPath | /bff/callback | Le chemin de l'URI de redirection OIDC. Il doit correspondre à celui enregistré pour le client. |
CookieName | __Host-agbff | Nom du cookie de session. Le préfixe __Host- exige HTTPS, un développement local en HTTP simple a donc besoin d'un autre nom. |
SessionLifetime | 8h | Durée de vie maximale d'une session. Alignez-la sur la durée de vie absolue de votre jeton de rafraîchissement, sinon un utilisateur inactif est déconnecté alors qu'il détient encore un jeton valide. |
PersistentCookie | false | Indique si le cookie survit à la fermeture du navigateur. Dans les deux cas, le jeton de rafraîchissement reste côté serveur. |
CorrelationLifetime | 30m | Le temps maximal que peut prendre une connexion entre son démarrage et le rappel. Cela borne le cookie qui porte le state, le nonce et le vérificateur PKCE : le cas auquel il doit survivre est celui d'un utilisateur qui laisse l'écran de connexion ouvert et y revient plus tard. |
RefreshThresholdSeconds | 60 | Combien de secondes avant l'expiration le jeton d'accès est rafraîchi. |
AntiForgeryHeader | X-Authagonal-Bff | Le nom de l'en-tête que le navigateur doit envoyer sur les requêtes qui ne sont pas des navigations. |
PostLogoutRedirectUri | - | L'endroit où le navigateur arrive une fois la déconnexion terminée. |
ReturnUrlAllowlist | [] | Les origines absolues qu'un returnUrl non relatif peut viser. Les chemins relatifs sont toujours autorisés et tout le reste est ramené à /, une redirection ouverte n'est donc pas atteignable par la route de connexion. |
LoginPassthroughParams | [] | Paramètres de requête transmis de /bff/login à la requête authorize, par exemple prompt, pour qu'un lien de démarrage mène à l'inscription plutôt qu'à la connexion. |
TenantQueryParam | - | Définissez-le pour servir plusieurs tenants depuis un seul BFF. Voir plus haut. |
Les deux runtimes se comportent de la même façon
StripPrefix, les contrôles d'autorité et le proxy anonyme sont propres à .NET. Les noms ci-dessus sont ceux de la version .NET ; Node utilise les équivalents en camelCase.Tout est remplaçable
IBffSessionStore pour l'endroit où vivent les sessions, ICookieProtector pour le chiffrement du cookie (ASP.NET Data Protection par défaut) et ITokenClient pour dialoguer avec les points de terminaison de jetons et de révocation. Un seul BFF peut aussi servir plusieurs tenants via IBffTenantResolver, en sélectionnant le tenant depuis un paramètre de requête à la connexion et en le résolvant depuis l'émetteur du jeton lors de la déconnexion back-channel.Pilotez votre portail depuis un assistant IA
Connectez un assistant IA à votre locataire et demandez-lui de faire ce que vous feriez autrement à la souris : trouver un utilisateur qui n'arrive pas à se connecter, vérifier s'il a toujours un second facteur, inviter quelqu'un, voir qui détient un rôle d'admin.
C'est une connexion OAuth ordinaire, pas une clé API. Chaque personne se connecte en son propre nom et approuve l'accès, un assistant peut donc faire exactement ce que cette personne peut faire dans le portail, et rien de plus. Rien de nouveau n'est créé qui pourrait fuiter, et révoquer un assistant laisse tous les autres intacts.
L'activer
Ouvrez les Paramètres et activez l'accès des assistants IA. Tant que vous ne l'avez pas fait, il est désactivé, et pendant qu'il est désactivé le point de terminaison n'existe pas au lieu de simplement refuser. Une fois activé, le panneau affiche l'URL à coller dans votre client IA :
https://portal-api.authagonal.io/api/v1/mcp/{your-tenant}Comment un assistant obtient l'autorisation
Ce qu'un assistant peut faire
Exactement ce que peut faire la personne qui l'a connecté, décidé à chaque appel à partir de son propre jeton. Un agent tenant:support obtient les outils de diagnostic et du quotidien ; les outils d'admin ne lui sont pas seulement masqués, ils sont refusés s'il les nomme directement. Tout ce qui est verrouillé dans le portail reste verrouillé : changer l'adresse e-mail d'un utilisateur exige le rôle d'admin là-bas, et il l'exige ici aussi.
Comme c'est un grant ordinaire, vous le gérez de façon ordinaire : retirez l'assistant sur la page Applications autorisées de votre compte et il ne peut plus se rafraîchir, il cesse donc de fonctionner à l'expiration de son jeton d'accès actuel. Chaque modification effectuée par un assistant est inscrite dans votre journal d'audit au nom de la personne pour laquelle il a agi, la trace est donc celle que vous lisez déjà.
Les outils
Trente-trois dans cette version. C'est votre client IA qui décide lesquels activer, vous pouvez donc ne confier à un assistant que les outils de lecture si c'est tout ce que vous voulez lui laisser faire.
| Outil | Rôle | Ce qu'il fait |
|---|---|---|
find_user | Support | Trouver des utilisateurs par e-mail, préfixe de nom ou id. Le point de départ de tout le reste. |
get_user | Support | Un utilisateur en entier, y compris s'il est actif, confirmé et verrouillé. |
get_user_mfa | Support | Quels seconds facteurs quelqu'un a enregistrés. |
get_user_sessions | Support | Où un utilisateur est actuellement connecté. |
search_audit | Support | Rechercher dans le journal d'audit par acteur, action ou objet concerné. |
list_users | Support | Lister l'annuaire, éventuellement filtré sur une seule organisation. |
get_user_stats | Support | Combien d'utilisateurs vous avez et combien utilisent un second facteur. |
invite_user | Support | Inviter quelqu'un par e-mail. |
resend_invite | Support | Renvoyer une invitation. |
send_verification_email | Support | Renvoyer le message de vérification d'e-mail. |
update_user | Support | Mettre à jour un profil. La modification de l'adresse e-mail exige toujours le rôle d'admin. |
revoke_user_sessions | Support | Déconnecter un utilisateur partout. |
list_roles | Admin | Les rôles définis dans votre locataire. |
list_role_members | Admin | Qui détient un rôle donné. |
assign_role | Admin | Donner un rôle à un utilisateur. |
unassign_role | Admin | Retirer un rôle. |
reset_user_mfa | Admin | Supprimer tous les seconds facteurs, pour quelqu'un qui a perdu son authentificateur. |
get_settings | Admin | La configuration de votre locataire. |
list_sso_connections | Admin | Vos connexions SSO et les domaines qu'elles couvrent. |
list_organizations | Admin | Les organisations de votre locataire, une page à la fois. |
get_organization | Admin | Une organisation par id ou slug, avec ses domaines e-mail. |
create_organization | Admin | Crée une organisation. Le slug est permanent. |
update_organization | Admin | Modifie le nom, les options de politique, les métadonnées ou l'image de marque d'une organisation. Le slug ne peut pas changer. |
delete_organization | Admin | Supprime une organisation et toutes ses appartenances. |
list_organization_members | Admin | Les membres d'une organisation, une page à la fois. |
add_organization_member | Admin | Ajoute un utilisateur à une organisation. |
update_organization_member | Admin | Modifie le statut ou les rôles d'un membre au sein d'une organisation. |
remove_organization_member | Admin | Retire un utilisateur d'une organisation. |
add_organization_domain | Admin | Revendique un domaine e-mail pour une organisation. Renvoie l'enregistrement DNS TXT à publier. |
verify_organization_domain | Admin | Vérifie l'enregistrement TXT et marque le domaine comme vérifié. Peut être répété sans risque. |
remove_organization_domain | Admin | Abandonne la revendication d'un domaine. Les membres existants restent. |
list_user_organizations | Admin | Les organisations auxquelles appartient un utilisateur, avec son statut et ses rôles dans chacune. |
list_clients | Développeur | Les clients OAuth enregistrés dans votre locataire. |
Lecture et écriture sont signalées
Ce qui n'est pas encore inclus
La suppression d'utilisateurs, la création ou la modification de connexions SSO, la facturation, les sauvegardes et les secrets client sont tous absents de cette version. La suppression relève de votre file d'attente d'effacement plutôt que d'un outil posé à côté ; une connexion SSO pèse assez lourd pour qu'une modification erronée bloque tout un effectif, ces éléments sont donc en lecture seule pour l'instant ; et un outil qui renverrait un secret client le déposerait dans la transcription d'un assistant. Dites-nous lesquels vous voulez, et dans quel ordre.
Authentification des serveurs MCP
Si vous exposez un serveur Model Context Protocol, Authagonal peut être le serveur d'autorisation derrière lui. Un assistant IA se connecte, la personne derrière lui s'authentifie et accorde l'accès, et votre serveur reçoit un jeton bearer ordinaire que vous validez comme pour n'importe quelle autre API.
L'alternative, c'est une clé API collée dans la configuration d'un assistant : un identifiant sans aucun utilisateur derrière lui, sans expiration, sans étape de consentement et sans moyen de révoquer un connecteur sans effectuer une rotation pour tout le monde. En passant par OAuth, le grant appartient à une personne identifiée, il est visible dans votre journal d'audit et il peut être révoqué depuis le portail sans toucher à quoi que ce soit d'autre.
Comment la connexion s'établit
Tout l'échange repose sur la découverte, un client conforme n'a donc rien à configurer d'autre que l'URL de votre serveur.
| Étape | Ce qui se passe |
|---|---|
| 1 | Le connecteur appelle votre serveur MCP sans jeton et reçoit un 401 qui indique où chercher. |
| 2 | Il récupère les métadonnées de votre ressource protégée, qui désignent votre locataire Authagonal comme serveur d'autorisation. |
| 3 | Il récupère les métadonnées du serveur d'autorisation du locataire et, n'ayant jamais été enregistré nulle part, s'enregistre lui-même. |
| 4 | Il envoie l'utilisateur se connecter et approuver l'accès, en désignant votre serveur MCP comme la ressource pour laquelle il veut un jeton. |
| 5 | Il rappelle votre serveur avec le jeton bearer obtenu, qui est limité à votre serveur et à cet utilisateur. |
Rien dans cette séquence n'est spécifique à Authagonal : c'est la spécification d'autorisation MCP, bâtie sur RFC 9728 pour les métadonnées de la ressource, RFC 8414 pour découvrir le serveur d'autorisation, RFC 7591 pour l'enregistrement et RFC 8707 pour désigner la ressource. Un connecteur qui suit la spécification fonctionne sans traitement particulier pour nous.
Laissez les connecteurs s'enregistrer eux-mêmes
Un connecteur que vous n'avez jamais rencontré ne peut pas utiliser un client que vous avez créé à la main, il en enregistre donc un à l'exécution. C'est désactivé par défaut. Activez l'enregistrement dynamique de clients dans les Paramètres et le point de terminaison d'enregistrement apparaît dans votre document de découverte ; laissez-le désactivé et le point de terminaison n'est pas annoncé et refuse. L'activer ouvre l'enregistrement pour votre locataire seul, jamais pour celui de quelqu'un d'autre.
| Garde-fou | Ce qui se passe |
|---|---|
| Types de grants | Seuls les flux authorization code et refresh peuvent être enregistrés. L'auto-enregistrement ne peut pas créer un client machine à machine qui contournerait entièrement un utilisateur. |
| PKCE | Imposé à tout client enregistré, quelle qu'ait été la demande d'enregistrement. |
| Consentement | Imposé également. Un connecteur enregistré ne peut pas obtenir de jeton tant qu'une personne n'a pas vu ce qu'il demande et ne l'a pas approuvé. |
| Portées | Les portées OIDC intégrées sont toujours disponibles. Au-delà, un client auto-enregistré ne peut demander qu'une portée nommée mcp, et uniquement une fois que votre locataire la définit sans restriction de rôle. roles et groups ne peuvent pas être obtenus par auto-enregistrement. |
| Limite de débit | Dix enregistrements par adresse IP et par heure, pour qu'un point de terminaison ouvert ne puisse pas servir à remplir votre référentiel de clients. |
Les deux chemins de découverte sont servis
/.well-known/oauth-authorization-server (RFC 8414), tandis que les clients OIDC utilisent /.well-known/openid-configuration. Votre locataire répond sur les deux avec les mêmes métadonnées, si bien qu'un connecteur qui suit la spécification MCP vous trouve sans qu'on lui indique où chercher.Ce que votre serveur MCP implémente
Deux petites choses, et ensuite c'est un serveur de ressources ordinaire. D'abord, publiez des métadonnées de ressource protégée qui désignent votre locataire comme serveur d'autorisation. Servez-les au chemin well-known et, si votre point de terminaison MCP se trouve sur un sous-chemin, également sous la forme suffixée par le chemin, car les clients essaient les deux.
GET https://your-app.example/.well-known/oauth-protected-resource
{
"resource": "https://your-app.example/mcp",
"authorization_servers": ["https://acme.authagonal.io"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["mcp"]
}Ensuite, quand un appel arrive sans jeton valide, répondez 401 avec un en-tête WWW-Authenticate pointant vers ces métadonnées. C'est cet en-tête qui transforme un refus en connexion : sans lui, le client n'a aucun moyen de découvrir où s'authentifier, et échoue purement et simplement.
// Validate the connector's token like any other resource server.
builder.Services.AddAuthentication().AddJwtBearer("McpBearer", o =>
{
o.Authority = "https://acme.authagonal.io"; // your tenant
o.TokenValidationParameters.ValidAudience = "https://your-app.example/mcp";
});
// Unauthenticated? Point the connector at the metadata rather than just refusing.
http.Response.Headers.WWWAuthenticate =
"Bearer resource_metadata=\"https://your-app.example/.well-known/oauth-protected-resource\"";
return Results.Unauthorized();Vérifiez l'audience, pas seulement la signature
Portées, plans et révocation
Définissez une portée nommée mcp sur votre page Portées, sans restriction de rôle, et un connecteur auto-enregistré pourra la demander ; elle apparaît sur l'écran de consentement pour que l'utilisateur voie ce qu'il approuve. Le sujet du jeton est la personne qui s'est connectée, de sorte que votre serveur peut décider ce que cette personne précise a le droit de faire plutôt que de traiter tous les connecteurs de la même façon. Un connecteur auto-enregistré ne peut pas demander les portées roles ou groups : récupérez donc ces informations de votre côté plutôt que de les attendre dans le jeton.
Comme il s'agit d'un grant OAuth ordinaire, la révocation fonctionne de façon ordinaire : l'utilisateur retire le connecteur sur la page Applications autorisées de son compte, ce qui supprime son grant et son jeton de rafraîchissement, de sorte qu'il ne peut plus se renouveler. Ses jetons d'accès existants sont immédiatement refusés par /connect/introspect et /connect/userinfo ; un serveur qui se contente de valider le JWT localement en accepte un jusqu'à son expiration. Le journal d'audit consigne chaque connexion avec le client concerné.
| Paramètre | Ce qui se passe |
|---|---|
Dynamic client registration | Paramètre du portail qui autorise les connecteurs à s'enregistrer eux-mêmes. Désactivé par défaut. |
mcp | La seule portée au-delà des portées OIDC intégrées qu'un client auto-enregistré peut demander. Définissez-la dans votre locataire, sans restriction de rôle, pour la proposer. |
resource | Le paramètre qu'un connecteur envoie pour désigner votre serveur MCP, ce qui restreint l'audience du jeton à celui-ci. |
Créer une interface de connexion personnalisée
Remplacez les écrans de connexion, d'inscription, de réinitialisation de mot de passe et de MFA hébergés par Authagonal par votre propre interface, pendant qu'Authagonal continue de gérer l'authentification, la MFA, le SSO, les sessions et l'émission de jetons. Deux approches : utiliser notre bibliothèque de composants React, ou appeler directement l'API d'authentification depuis n'importe quel framework. C'est une option à activer : activez d'abord Interface de connexion personnalisée sous Paramètres → Session.


Prérequis : un domaine personnalisé sur votre racine
La session de connexion est un cookie first-party, votre interface et le serveur d'authentification Authagonal doivent donc partager un domaine enregistrable. Pointez un domaine d'authentification personnalisé vers Authagonal sur la même racine que celle de votre application — par ex. l'authentification sur login.acme.com, l'application sur app.acme.com. Le paramètre Custom login UI reste désactivé tant qu'aucun domaine personnalisé actif n'existe.
| Votre interface | Hôte d'authentification | Fonctionne ? |
|---|---|---|
| app.acme.com | login.acme.com | ✅ même racine |
| acme.com | auth.acme.com | ✅ même racine |
| app.acme.com | acme.authagonal.io | ❌ cross-site |
| myapp.io | login.acme.com | ❌ cross-site |
Pourquoi un domaine personnalisé est requis
Aucun paramètre CORS du client n'est nécessaire pour les appels /api/auth : dès que Interface de connexion personnalisée est activée, toute origine sur le même domaine enregistrable que votre domaine d'authentification est admise automatiquement. Ajoutez l'origine de votre interface (par ex. https://app.acme.com) aux Origines CORS autorisées du client (Clients → URIs) uniquement si le navigateur effectue aussi l'échange de jetons.
React : @authagonal/login
npm i @authagonal/login fournit la logique d'authentification et l'interface dans un seul paquet — le même que celui sur lequel repose la connexion hébergée par Authagonal. Choisissez votre niveau :
- Application complète — intégrez
Appet personnalisez-la via le branding. - Composer des pages — utilisez
LoginPage,MfaChallengePage,ResetPasswordPage… dans votre propre mise en page. - Primitives + logique — créez vos propres écrans avec
AuthLayout/Button/Inputet le client API (login,mfaVerify,forgotPassword, …).
import { AuthLayout, Input, Button, login, ApiRequestError } from '@authagonal/login';
// returnUrl: the /connect/authorize URL your login page was opened with
function MyLogin({ returnUrl }: { returnUrl: string }) {
async function onSubmit(email: string, password: string) {
try {
const res = await login(email, password, returnUrl); // POST /api/auth/login (sets the session cookie)
if (res.mfaRequired) {/* render your MFA step, then mfaVerify(res.challengeId!, 'totp', code) */}
else if (res.mfaSetupRequired) {/* enrol first: mfaTotpSetup(res.setupToken) */}
else window.location.href = returnUrl; // resume /connect/authorize
} catch (e) {
if (e instanceof ApiRequestError) {/* show e.message; e.error is the error code */}
}
}
return <AuthLayout>{/* your own markup + <Input/> <Button/> */}</AuthLayout>;
}N'importe quel framework : appeler l'API d'authentification
Pas sur React ? Appelez directement les points de terminaison du flux d'authentification (sous /api/auth), puis basculez vers le flux OIDC standard /connect/authorize. Envoyez credentials: 'include' pour que le cookie de session soit stocké.
| Point de terminaison | Objectif |
|---|---|
POST /api/auth/login | Authentifié ; renvoie mfaRequired ou une URL de retour |
POST /api/auth/register | Inscription en libre-service (lorsque activée) |
POST /api/auth/forgot-password | Démarre une réinitialisation de mot de passe |
POST /api/auth/reset-password | Termine une réinitialisation de mot de passe |
GET /api/auth/password-policy | Politique de mot de passe (pour afficher les règles) |
POST /api/auth/mfa/* | Configuration + vérification MFA (TOTP, WebAuthn, récupération) |
Utilisez credentials: 'include'
# 1. Authenticate (browser fetch; credentials:'include' so the session cookie is stored)
curl -i -X POST https://login.acme.com/api/auth/login \
-H "Content-Type: application/json" \
-H "Origin: https://app.acme.com" \
--data '{"email":"[email protected]","password":"..."}'
# (handle {"mfaRequired":true} → POST /api/auth/mfa/verify, then continue)
# 2. Hand off to the OAuth flow: top-level navigation to the authorize endpoint with PKCE:
# https://login.acme.com/connect/authorize?client_id=my-app&redirect_uri=...&response_type=code
# &scope=openid%20profile%20email&code_challenge=...&code_challenge_method=S256
# The session cookie (same-site) authenticates the user; you get back a code → exchange at /connect/token.Un tenant, de nombreux clients
Un schéma pour un intégrateur, un tenant et N clients à leur image, chacun avec son propre domaine de connexion et ses propres utilisateurs, sans un tenant par client. C'est ce que le provisionnement déclaratif et les organisations permettent de transformer en simple changement de configuration plutôt qu'en tâche d'ingénierie.
Le schéma
- Une organisation par client, au sein d'un seul tenant.
- Un domaine de connexion à l'image de chaque client, rattaché à l'organisation de ce client : se connecter dessus ne peut jamais produire qu'un jeton pour cette organisation.
- L'application est aussi servie par hôte client, depuis le même déploiement : rien dans le code, le build ou l'image ne diffère d'un client à l'autre.
- La partie utilisatrice (relying party) choisit son autorité d'après l'hôte sur lequel elle s'exécute, et non d'après une constante de build : le même bundle se connecte à un domaine de connexion différent selon l'hôte client qui l'a servi.
Étape par étape
Provisionner le client. Appelez le point de terminaison de provisionnement déclaratif avec une spécification nommant la nouvelle organisation et son domaine. L'appel est idempotent et limité à une section.
{
"organizations": [
{ "slug": "acme", "name": "Acme Pty Ltd" }
],
"customDomains": [
{ "domain": "login.acme.example", "organizationSlug": "acme" }
]
}Pointer le DNS du client vers le tenant. Un seul CNAME depuis la propre zone du client, prouvant le contrôle et l'intention, sans jeton TXT.
_authagonal-challenge.login.acme.example. CNAME <slug>.<platformDomain>.
Même compte Cloudflare que la plateforme ?
Pointer l'application vers l'hôte du client. La partie utilisatrice résout sa propre autorité OIDC à chaque requête, d'après l'hôte qu'elle sert actuellement : un hôte sans entrée dans la table des clients retombe sur la dérivation classique à un seul tenant, donc ajouter un client est purement additif.
export function resolveCustomer(): { authority: string; clientId: string } {
const cfg = getConfig();
const customer = cfg.customers?.[window.location.host];
if (customer) return customer;
const baseDomain = cfg.baseDomain || window.location.hostname.replace(/^consumer\./, '');
return { authority: `https://${cfg.tenantSlug}.${baseDomain}`, clientId: cfg.clientId };
}Le client ne demande rien de propre à l'organisation : ni paramètre organization, ni portée par client. Le rattachement de domaine fait toute la sélection de l'organisation côté serveur, ce qui rend « l'application est le même code pour chaque client » réellement vrai.
Ce que voit le client
La page de connexion affiche l'image de marque propre à chaque organisation fusionnée sur celle du tenant. Voir Personnalisation de l'image de marque. Chaque client peut avoir son propre nom d'application, son logo, sa couleur et son e-mail de support sans toucher aux autres.
Un utilisateur du client A qui tente de se connecter sur l'hôte du client B est refusé, sans qu'on lui montre les données du client B, sous l'une de deux formes selon l'origine du conflit :
- La partie utilisatrice n'envoie rien et arrive simplement sur le domaine rattaché : le rattachement fournit l'organisation à la place de l'utilisateur, la sélection devient alors explicite, et un utilisateur du client A sans appartenance à B est refusé au moment où le jeton serait émis.
- La partie utilisatrice nomme elle-même une organisation différente : refusé directement par le middleware de rattachement de domaine avec un
400, avant l'affichage de toute page de connexion.
Le refus d'appartenance redirige vers l'application
error=access_denied vers le redirect_uri de la partie utilisatrice, avec une description qui nomme précisément l'appartenance à l'organisation qui manquait.Intégrer le client N+1
Avec Terraform qui pilote l'appel de provisionnement, intégrer un client de plus revient à modifier un seul fichier : une entrée de plus dans le tableau des organisations, une entrée de domaine de plus pour le rattacher, un enregistrement DNS de plus. Rien dans l'application, son déploiement ou son build ne change : le résolveur basé sur l'hôte prend en compte le nouveau client dès que son entrée de configuration existe.
Implémentation de référence
Un tenant de développement persistant exerce tout ce schéma de bout en bout sur deux vrais domaines clients, avec une suite de tests de bout en bout qui provisionne des membres, vérifie l'image de marque et la revendication org_id, et valide les deux formes de refus ci-dessus : une documentation exécutable, pas seulement une description.
cd e2e-consumer && DOMAIN=authagonal.dev npx playwright test organizations-domains
La suite s'exécute par défaut comme tous les autres tests ; elle peut être ignorée dans un environnement où les domaines de référence ne sont pas provisionnés, car c'est le seul test de la suite qui dépend d'une infrastructure hors du contrôle du dépôt.
Plans et limites
Authagonal propose un plan Free et quatre niveaux payants. Chaque plan inclut toutes les fonctionnalités d'authentification. Les plans diffèrent par la limite d'utilisateurs actifs mensuels (MAU) et la tarification des dépassements, et le plan Free n'offre que le support communautaire, sans le service de support client du locataire.
Niveaux de plan
| Plan | Limite MAU | Dépassement | Coût de dépassement/utilisateur |
|---|---|---|---|
| Free | 250 | Non | — |
| Starter | 1,000 | Non | — |
| Pro | 5 000 | Oui | 0,04 $/utilisateur |
| Scale | 25 000 | Oui | 0,025 $/utilisateur |
| Enterprise | 100 000 | Oui | 0,015 $/utilisateur |
Utilisateurs actifs mensuels (MAU)
Un utilisateur actif mensuel est tout utilisateur unique qui s'authentifie avec succès au moins une fois au cours d'un mois civil (UTC). Les utilisateurs provisionnés via SCIM mais qui ne se sont pas connectés ne comptent pas dans votre total MAU.
Dépassement : si votre plan prend en charge le dépassement (Pro et au-delà) et que le dépassement est activé pour votre locataire (il est désactivé par défaut), les utilisateurs au-delà de la limite MAU sont facturés au tarif par utilisateur indiqué dans le tableau des plans ci-dessus. Un plafond de dépassement fixe le nombre maximal d'utilisateurs supplémentaires autorisés au-delà de la limite.
Application : si votre plan ne prend pas en charge le dépassement (Free, Starter) ou si le dépassement n'est pas activé, les utilisateurs qui se sont déjà connectés ce mois-ci conservent toujours leur accès. Lorsque le locataire dépasse sa limite pour la première fois, une période de grâce de 10 jours commence, pendant laquelle les nouveaux utilisateurs peuvent encore se connecter. Ensuite, les utilisateurs qui ne se sont pas connectés ce mois-ci sont refusés jusqu'au mois suivant ou jusqu'à ce que vous passiez à un plan supérieur.
Toutes les fonctionnalités dans chaque plan