Aller au contenu principal

Se connecter avec Microsoft Entra ID (Azure AD) dans Capacitor

Ajouter la connexion Microsoft Entra ID (Azure AD) à une application Capacitor 8 avec PKCE : enregistrement de l'application, URI de redirection, scopes Graph et API, et résolution des erreurs AADSTS.

Page de connexion Microsoft Entra ID lancée depuis une application Capacitor

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

  1. Ouvrez le Centre d'administration Microsoft Entra et accédez à Entra ID > Enregistrements d'applications > Nouvel enregistrement.
  2. Saisissez un nom, par exemple « Example Mobile ».
  3. Choisissez Types de compte pris en charge. Cela détermine l’autorité que vous utiliserez plus tard.
  4. Ignorez l’URI de redirection pour le moment et cliquez sur S'inscrire.
  5. 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/azure en tant qu'URI de redirection personnalisée. Ajoutez com.example.app://oauth/logout too 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 :

  1. Ouvrez Exposer un API et définir l'URI d'identifiant d'application, généralement api://<client-id>.
  2. Ajouter un scope nommé access_as_user, who can consent: Admins and users.
  3. Dans Manifest, définissez "requestedAccessTokenVersion": 2 pour 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.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.