Pour vous connecter avec Microsoft Entra ID (anciennement Azure Active Directory) dans une application Capacitor, enregistrez une application cliente publique dans le centre d'administration Entra, ajoutez une Applications mobiles et de bureau URI de redirection telle que com.example.app://oauth/azure, et exécutez le flux d'autorisation OpenID Connect code avec PKCE via le navigateur système. Avec @capgo/capacitor-social-login cela signifie un initialize appel avec les endpoints de la plateforme d'identité Microsoft v2.0 et SocialLogin.login({ provider: 'oauth2', options: { providerId: 'azure' } }).
Ce guide couvre l'enregistrement de l'application, le choix de l'autorité, les scopes Graph et API personnalisés, la validation du token, l'accès conditionnel, la déconnexion et les erreurs AADSTS que vous rencontrerez. Il cible Capacitor 8 en octobre 2026.
Ce dont vous avez besoin
- Un tenant Microsoft Entra et un rôle permettant de créer des enregistrements d'applications (Développeur d'applications ou supérieur).
- Une application Capacitor 8 et son
appId, que vous réutiliserez comme schéma de redirection. - En option, un backend API qui doit accepter les tokens Entra.
Pourquoi pas MSAL.js dans le WebView
MSAL.js est conçu pour les navigateurs qui contrôlent leur origine et peuvent ouvrir des popups. Dans un WebView Capacitor, l’origine est capacitor://localhost sur iOS et https://localhost sur Android, les popups sont bloquées, et une redirection pleine page ferait sortir votre application de son propre bundle. Microsoft recommande, pour les applications natives, le navigateur système avec PKCE (RFC 8252), ce que fait le plugin :
| Plateforme | Navigateur utilisé | Extra setup |
|---|---|---|
| iOS | ASWebAuthenticationSession |
Aucun |
| Android | Chrome Custom Tabs avec androidUseCustomTabs: true |
Filtre d'intent |
| Le Web | Popup ou redirection | URI de redirection SPA |
Sur Android, activez les Custom Tabs. Le WebView intégré par défaut ne peut pas communiquer avec Microsoft Authenticator, les passkeys ou le Company Portal, sur lesquels l'accès conditionnel s'appuie souvent.
Étape 1 : Enregistrer l'application dans Entra ID
- Ouvrez le Centre d'administration Microsoft Entra et accédez à Entra ID > Enregistrements d'applications > Nouvel enregistrement.
- Saisissez un nom, par exemple « Example Mobile ».
- Choisissez Types de compte pris en charge. Cela détermine l’autorité que vous utiliserez plus tard.
- Ignorez l’URI de redirection pour le moment et cliquez sur S'inscrire.
- Activé Aperçu, copiez l' ID d'application (client) et ID de répertoire (tenant).
Choisissez l'autorité
| Type de compte à l'inscription | Segment d'autorité dans les URL |
|---|---|
| Tenant unique (votre organisation uniquement) | Votre ID de tenant, par exemple 8f1c... |
| Tout annuaire organisationnel | organizations |
| Tout annuaire organisationnel et les comptes Microsoft personnels | common |
| Comptes Microsoft personnels uniquement | consumers |
Utilisez l’ID de tenant chaque fois que possible. Il génère des émetteurs prévisibles et évite les connexions accidentelles depuis d’autres tenants.
Ajouter des URI de redirection
Accéder à Authentification > Ajouter une plateforme:
- Applications mobiles et de bureau: ajouter
com.example.app://oauth/azureen tant qu'URI de redirection personnalisée. Ajoutezcom.example.app://oauth/logouttoo if you want a post-logout redirect. - Application monopage (uniquement si vous publiez un build web) : ajoutez
https://app.example.com/auth/callback.
Ne pas enregistrer l'URI mobile sous Le WebLes redirections de la plateforme Web sont des clients confidentiels et nécessitent un secret sur le point de terminaison du token.
les permissions API
les permissions API contient déjà Microsoft Graph > User.Read. Ajoutez offline_access, openid, profile et email s'ils ne sont pas listés. Certains tenants bloquent le consentement utilisateur. Dans ce cas, un administrateur doit cliquer sur Accorder le consentement administrateur, otherwise users see AADSTS65001 or a “Need admin approval” screen.
Exposer un scope pour votre propre API (facultatif)
Si votre backend doit accepter le token :
- Ouvrez Exposer un API et définir l'URI d'identifiant d'application, généralement
api://<client-id>. - Ajouter un scope nommé
access_as_user, who can consent: Admins and users. - Dans Manifest, définissez
"requestedAccessTokenVersion": 2pour que les tokens d'accès utilisent le format d'émetteur v2.0.
Étape 2 : Installer le plugin et ajouter le filtre d'intent
bun add @capgo/capacitor-social-login
bunx cap sync
Dans android/app/src/main/AndroidManifest.xml, à l'intérieur MainActivity:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.example.app" android:host="oauth" />
</intent-filter>
Conservez android:launchMode="singleTask" sur MainActivity (la valeur par défaut Capacitor). Si vous n'utilisez pas la connexion Google, Apple ou Facebook, désactivez-les sous plugins.SocialLogin.providers dans capacitor.config.ts pour éviter d'inclure leurs SDK dans le build.
Étape 3 : Initialiser le fournisseur Entra ID
import { Capacitor } from '@capacitor/core';
import { SocialLogin } from '@capgo/capacitor-social-login';
const TENANT = 'YOUR_TENANT_ID'; // or organizations / common
const AUTHORITY = `https://login.microsoftonline.com/${TENANT}/oauth2/v2.0`;
const isWeb = Capacitor.getPlatform() === 'web';
export async function initAuth() {
await SocialLogin.initialize({
oauth2: {
azure: {
appId: 'YOUR_CLIENT_ID',
authorizationBaseUrl: `${AUTHORITY}/authorize`,
accessTokenEndpoint: `${AUTHORITY}/token`,
redirectUrl: isWeb
? 'https://app.example.com/auth/callback'
: 'com.example.app://oauth/azure',
scope: 'openid profile email offline_access User.Read',
pkceEnabled: true,
resourceUrl: 'https://graph.microsoft.com/v1.0/me',
logoutUrl: `${AUTHORITY}/logout`,
postLogoutRedirectUrl: isWeb ? 'https://app.example.com/' : 'com.example.app://oauth/logout',
androidUseCustomTabs: true,
},
},
});
}
Avec resourceUrl pointant vers Graph /me, le plugin appelle Graph juste après la connexion et renvoie le profil dans resourceData.
Si vous migrez depuis Ionic Auth Connect, SocialLoginAuthConnect a un azure préréglage qui ne nécessite que tenantId, clientId et redirectUrl. Consultez la page d'intégration Entra ID.
Étape 4 : Connexion
import { SocialLogin } from '@capgo/capacitor-social-login';
export async function signInWithMicrosoft() {
try {
const { result } = await SocialLogin.login({
provider: 'oauth2',
options: { providerId: 'azure' },
});
const me = result.resourceData as {
id: string;
displayName?: string;
mail?: string | null;
userPrincipalName?: string;
} | null;
return {
idToken: result.idToken,
graphToken: result.accessToken?.token,
refreshToken: result.refreshToken,
user: me,
};
} catch (error: any) {
if (error?.code === 'USER_CANCELLED') return null;
throw error;
}
}
Options utiles :
loginHint: 'jane@contoso.com'préremplit le compte et ignore le sélecteur de compte pour cet utilisateur.prompt: 'select_account'affiche toujours le sélecteur de compte, utile pour les appareils partagés.additionalParameters: { domain_hint: 'contoso.com' }redirige directement les utilisateurs vers leur IdP fédéré.
mail est souvent null pour les comptes sans boîte mail. À défaut, utilisez userPrincipalName ou la preferred_username claim du token ID.
Étape 5 : Appeler Microsoft Graph
export async function getMyPhotoBlob(graphToken: string) {
const res = await fetch('https://graph.microsoft.com/v1.0/me/photo/$value', {
headers: { Authorization: `Bearer ${graphToken}` },
});
if (res.status === 404) return null; // no photo set
if (!res.ok) throw new Error(`Graph error ${res.status}`);
return res.blob();
}
Ajoutez chaque scope Graph nécessaire (par exemple Calendars.Read) à la fois dans les permissions API et dans la scope chaîne.
Étape 6 : Obtenir un token pour votre propre API
Un token d'accès cible une ressource. Pour appeler votre backend, ajoutez une deuxième entrée à côté de azure dans la même oauth2 map de votre initialize appel, en demandant votre scope API au lieu de Graph :
await SocialLogin.initialize({
oauth2: {
azure: graphConfig, // the object from step 3, moved into a const
azureApi: {
appId: 'YOUR_CLIENT_ID',
authorizationBaseUrl: `${AUTHORITY}/authorize`,
accessTokenEndpoint: `${AUTHORITY}/token`,
redirectUrl: 'com.example.app://oauth/azure-api', // register this URI too
scope: 'openid profile offline_access api://YOUR_CLIENT_ID/access_as_user',
pkceEnabled: true,
androidUseCustomTabs: true,
},
},
});
L'utilisateur possède déjà une session Microsoft, la seconde connexion se fait donc généralement sans prompt. Validez le token sur le serveur :
import { createRemoteJWKSet, jwtVerify } from 'jose';
const TENANT_ID = 'YOUR_TENANT_ID';
const jwks = createRemoteJWKSet(
new URL(`https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys`),
);
export async function verifyEntraToken(token: string) {
const { payload } = await jwtVerify(token, jwks, {
issuer: `https://login.microsoftonline.com/${TENANT_ID}/v2.0`,
audience: 'YOUR_CLIENT_ID', // v2 tokens use the client ID as aud
});
if (!String(payload.scp ?? '').split(' ').includes('access_as_user')) {
throw new Error('Missing scope');
}
return payload; // payload.oid is the stable user object ID
}
Pour les apps multitenant, l'issuer contient l'ID du tenant de chaque client. Validez le tid claim par rapport à la liste des tenants acceptés plutôt qu'à un issuer fixe. Les utilisateurs clés sur oid , ce qui tid, et non sur l'e-mail.
Étape 7 : Rafraîchir et se déconnecter
// Get a valid Graph token, refreshing it when it has expired
export async function getGraphToken() {
const { isLoggedIn } = await SocialLogin.isLoggedIn({ provider: 'oauth2', providerId: 'azure' });
if (!isLoggedIn) {
try {
await SocialLogin.refresh({ provider: 'oauth2', options: { providerId: 'azure' } });
} catch {
// no session, or the refresh token expired or was revoked
const loginResult = await signInWithMicrosoft();
if (!loginResult) throw new Error('Sign-in cancelled');
}
}
const { accessToken } = await SocialLogin.getAuthorizationCode({ provider: 'oauth2', providerId: 'azure' });
return accessToken;
}
// Sign out
await SocialLogin.logout({ provider: 'oauth2', providerId: 'azure' });
Les refresh tokens Entra pour les clients publics durent jusqu'à 90 jours avec une fenêtre glissante et sont remplacés à chaque utilisation. Le plugin stocke le nouveau. Si vous stockez vous-même les tokens, utilisez le Keychain ou le Keystore, par exemple NativeBiometric.setData depuis @capgo/capacitor-native-biometric, et passez-les à SocialLogin.refreshToken.
logout efface les tokens locaux et ouvre l'endpoint de logout v2.0 dans le navigateur système. Microsoft affiche parfois une page « Vous vous êtes déconnecté de votre compte » au lieu de rediriger vers un schéma personnalisé, l'utilisateur devra donc parfois la fermer. Si vous n'avez besoin que d'un logout local, omettez logoutUrl et passez prompt: 'select_account' lors de la prochaine connexion.
Accès conditionnel et Intune
L'OIDC via navigateur fonctionne avec le MFA, le passwordless et la plupart des politiques d'accès conditionnel. Deux cas nécessitent davantage :
- Exiger un appareil conforme ou en mode hybride: Entra doit pouvoir vérifier l'état de l'appareil. Sur Android, cela fonctionne via les Custom Tabs si Company Portal ou Authenticator est installé. Sur les appareils iOS gérés, le plug-in Microsoft Enterprise SSO déployé par votre MDM assure cette fonction. Testez ce point tôt avec une politique réelle.
- Politiques de protection des applications Intune (MAM): cela nécessite l'application Intune SDK à l'intérieur de l'application native. L'OIDC seul ne permet pas de satisfaire les autorisations « Require app protection policy ».
Troubleshooting
| Erreur | Signification | Corriger |
|---|---|---|
| AADSTS50011 | Redirect URI incorrect | Ajoutez l’URI exacte sous Applications mobiles et de bureau |
| AADSTS7000218 | La requête de token nécessite un secret | La redirection était enregistrée sous Web. Déplacez-la vers Applications mobiles et de bureau |
| AADSTS9002326 | L’échange de token cross-origin n’est autorisé que pour les SPA | Le build web utilise une redirection mobile. Enregistrez l’URL web sous Application monopage |
| AADSTS700016 | Application introuvable dans l’annuaire | Tenant incorrect dans l’autorité, ou application mono-tenant utilisée avec common |
| AADSTS50020 | Compte utilisateur d’un autre tenant | Utilisez une inscription multi-tenant, ou invitez l’utilisateur en tant qu’invité |
| AADSTS65001 | Consentement non accordé | Grant admin consent or allow user consent |
| AADSTS53003 | Bloqué par l’accès conditionnel | Consultez les logs de connexion, voir la section ci-dessus |
| AADSTS28000 | Scopes pour plusieurs ressources dans une seule requête | Demandez les scopes Graph et API lors de connexions séparées |
| Aucun refresh token | offline_access manquant |
Ajoutez-l’aux scopes et autorisations |
Le centre d’administration Entra Logs de connexion affichent la raison exacte de l’échec pour chaque tentative, et logsEnabled: true dans la config du plugin, affiche l’URL d’autorisation et la réponse token sur l’appareil.
Déployer des mises à jour
Les modifications de stratégie côté Entra sont instantanées, mais les correctifs côté client doivent encore atteindre les appareils. Les modifications TypeScript, comme les scopes ou la gestion des erreurs, peuvent être livrées via les live updates Capgo. Les modifications natives (intent filters, nouveaux schémas) nécessitent un nouveau build pour les stores, que Build Capgo peut générer sans Mac local.