Langsung ke konten utama

Login dengan Microsoft Entra ID (Azure AD) di Capacitor

Tambahkan login Microsoft Entra ID (Azure AD) ke aplikasi Capacitor 8 dengan PKCE: registrasi aplikasi, redirect URI, scope Graph dan API, serta perbaikan error AADSTS.

Halaman sign-in Microsoft Entra ID yang diluncurkan dari aplikasi Capacitor

Untuk sign-in dengan Microsoft Entra ID (sebelumnya Azure Active Directory) di aplikasi Capacitor, daftarkan aplikasi klien publik di pusat admin Entra, tambahkan Aplikasi mobile dan desktop redirect URI seperti com.example.app://oauth/azure, dan jalankan alur otorisasi OpenID Connect code dengan PKCE melalui browser sistem. Dengan @capgo/capacitor-social-login artinya satu initialize panggilan dengan endpoint platform identitas Microsoft v2.0 dan SocialLogin.login({ provider: 'oauth2', options: { providerId: 'azure' } }).

Panduan ini mencakup pendaftaran aplikasi, memilih authority yang tepat, scope Graph dan API kustom, validasi token, Conditional Access, logout, dan error AADSTS yang akan Anda lihat. Ini menargetkan Capacitor 8 pada Oktober 2026.

Yang Anda butuhkan

  • Tenant Microsoft Entra dan peran yang dapat membuat pendaftaran aplikasi (Application Developer atau lebih tinggi).
  • Aplikasi Capacitor 8 dan appId, yang akan Anda gunakan kembali sebagai redirect scheme.
  • Opsional, backend API yang harus menerima token Entra.

Mengapa tidak menggunakan MSAL.js di dalam WebView

MSAL.js dirancang untuk browser yang memiliki origin sendiri dan dapat membuka popup. Di WebView Capacitor, origin-nya adalah capacitor://localhost pada iOS dan https://localhost di Android, popup diblokir, dan redirect halaman penuh akan mengalihkan aplikasi Anda dari bundle-nya sendiri. Panduan Microsoft untuk aplikasi native adalah browser sistem dengan PKCE (RFC 8252), yang dilakukan oleh plugin ini:

Platform Browser yang digunakan Setup tambahan
iOS ASWebAuthenticationSession Tidak ada
Android Chrome Custom Tabs dengan androidUseCustomTabs: true Intent filter
Web Popup atau redirect URI redirect SPA

Di Android, aktifkan Custom Tabs. WebView bawaan yang tertanam tidak dapat berkomunikasi dengan Microsoft Authenticator, passkeys, atau Company Portal, yang sering diandalkan oleh Conditional Access.

Langkah 1: Daftarkan aplikasi di Entra ID

  1. Buka Pusat admin Microsoft Entra dan buka Entra ID > App registrations > New registration.
  2. Masukkan nama, misalnya “Example Mobile”.
  3. Pilih Jenis akun yang didukung. Ini menentukan authority yang Anda gunakan nanti.
  4. Lewati redirect URI dulu dan klik Daftar.
  5. Di Ikhtisar, salin ID Aplikasi (client) dan ID Direktori (tenant).

Pilih authority

Tipe akun saat registrasi Segmen authority di URL
Single tenant (hanya org Anda) Tenant ID Anda, misalnya 8f1c...
Direktori organisasi mana pun organizations
Direktori organisasi mana pun plus akun Microsoft pribadi common
Hanya akun Microsoft pribadi consumers

Gunakan tenant ID setiap kali memungkinkan. Ini menghasilkan issuer yang dapat diprediksi dan menghindari sign-in yang tidak disengaja dari tenant lain.

Tambahkan URI redirect

Buka Autentikasi > Tambahkan platform:

  • Aplikasi mobile dan desktop: tambah com.example.app://oauth/azure sebagai URI redirect kustom. Tambahkan com.example.app://oauth/logout juga jika Anda ingin redirect setelah logout.
  • Aplikasi single-page (hanya jika Anda merilis web build): tambahkan https://app.example.com/auth/callback.

Jangan daftarkan URI mobile di bawah Web. Redirect platform web adalah confidential client dan memerlukan secret di token endpoint.

API permissions

API permissions sudah berisi Microsoft Graph > User.Read. Tambahkan offline_access, openid, profile dan email jika tidak terdaftar. Beberapa tenant memblokir persetujuan pengguna. Dalam hal ini, admin harus mengklik Beri persetujuan admin, jika tidak pengguna akan melihat AADSTS65001 atau layar “Butuh persetujuan admin”.

Ekspos scope untuk API Anda sendiri (opsional)

Jika backend Anda harus menerima token:

  1. Buka Ekspos API dan atur Application ID URI, biasanya api://<client-id>.
  2. Tambahkan scope bernama access_as_user, who can consent: Admins and users.
  3. Di Manifest, setel "requestedAccessTokenVersion": 2 sehingga access token menggunakan format issuer v2.0.

Langkah 2: Instal plugin dan tambahkan intent filter

bun add @capgo/capacitor-social-login
bunx cap sync

Di android/app/src/main/AndroidManifest.xml, di dalam 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>

Pertahankan android:launchMode="singleTask" aktif MainActivity (default Capacitor). Jika Anda tidak menggunakan login Google, Apple, atau Facebook, nonaktifkan di bawah plugins.SocialLogin.providers di capacitor.config.ts untuk menjaga SDK mereka agar tidak masuk ke build.

Langkah 3: Inisialisasi provider 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,
      },
    },
  });
}

Dengan resourceUrl yang mengarah ke Graph /me, plugin memanggil Graph tepat setelah login dan mengembalikan profil di resourceData.

Jika Anda bermigrasi dari Ionic Auth Connect, SocialLoginAuthConnect memiliki azure preset yang hanya perlu tenantId, clientId dan redirectUrl. Lihat halaman integrasi Entra ID.

Langkah 4: Masuk

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;
  }
}

Opsi yang berguna:

  • loginHint: 'jane@contoso.com' mengisi otomatis akun dan melewati account picker untuk user tersebut.
  • prompt: 'select_account' selalu menampilkan account picker, berguna untuk perangkat bersama.
  • additionalParameters: { domain_hint: 'contoso.com' } mengarahkan user langsung ke federated IdP mereka.

mail sering kali null untuk akun tanpa mailbox. Gunakan fallback ke userPrincipalName atau preferred_username claim dari ID token.

Langkah 5: Panggil 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();
}

Tambahkan setiap Graph scope yang Anda butuhkan (misalnya Calendars.Read) di kedua API permissions dan di scope string.

Langkah 6: Dapatkan token untuk API Anda sendiri

Access token menargetkan satu resource. Untuk memanggil backend Anda, tambahkan entri kedua di samping azure di oauth2 map yang sama pada initialize panggilan Anda, meminta scope API Anda alih-alih 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,
    },
  },
});

Pengguna sudah memiliki sesi Microsoft, jadi login kedua biasanya selesai tanpa prompt. Validasi token di server:

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
}

Untuk aplikasi multitenant, issuer berisi tenant ID setiap pelanggan. Validasi tid claim terhadap daftar tenant yang Anda terima, bukan issuer tetap. Kunci pengguna pada oid plus tid, bukan pada email.

Langkah 7: Refresh dan keluar

// 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' });

Entra refresh token untuk klien publik berlaku hingga 90 hari dengan sliding window dan diganti setiap kali digunakan. Plugin menyimpan token baru tersebut. Jika Anda menyimpan token sendiri, gunakan Keychain atau Keystore, misalnya NativeBiometric.setData dari @capgo/capacitor-native-biometric, dan teruskan ke SocialLogin.refreshToken.

logout menghapus token lokal dan membuka endpoint logout v2.0 di browser sistem. Microsoft kadang menampilkan halaman “You signed out of your account” alih-alih mengarahkan ke skema kustom, sehingga pengguna mungkin harus menutupnya. Jika Anda hanya perlu logout lokal, hilangkan logoutUrl dan teruskan prompt: 'select_account' pada login berikutnya.

Conditional Access dan Intune

OIDC berbasis browser berfungsi dengan MFA, passwordless, dan sebagian besar kebijakan Conditional Access. Dua kasus butuh lebih:

  • Wajibkan perangkat compliant atau hybrid-joined: Entra harus melihat status perangkat. Di Android, ini berjalan melalui Custom Tabs jika Company Portal atau Authenticator terpasang. Di perangkat iOS yang dikelola, plug-in Microsoft Enterprise SSO yang di-deploy oleh MDM Anda menyediakannya. Uji ini lebih awal dengan kebijakan nyata.
  • Kebijakan perlindungan aplikasi Intune (MAM): ini memerlukan Intune App SDK di dalam aplikasi native. OIDC saja tidak memenuhi grant “Require app protection policy”.

Pemecahan Masalah

Error Arti Perbaikan
AADSTS50011 Redirect URI tidak cocok Tambahkan URI yang tepat di bagian Mobile and desktop applications
AADSTS7000218 Permintaan token memerlukan secret Redirect terdaftar di Web. Pindahkan ke Mobile and desktop
AADSTS9002326 Penukaran token cross-origin hanya diizinkan untuk SPA Build web memakai redirect mobile. Daftarkan URL web di Single-page application
AADSTS700016 App tidak ditemukan di direktori Tenant salah di authority, atau app single-tenant dipakai dengan common
AADSTS50020 Akun pengguna dari tenant lain Gunakan registrasi multitenant, atau undang pengguna sebagai guest
AADSTS65001 Consent tidak diberikan Berikan admin consent atau izinkan user consent
AADSTS53003 Diblokir oleh Conditional Access Cek sign-in logs, lihat bagian di atas
AADSTS28000 Scope untuk lebih dari satu resource dalam satu request Request scope Graph dan API dalam login terpisah
Tidak ada refresh token offline_access hilang Tambahkan ke scopes dan permissions

Entra admin center Log masuk menampilkan alasan kegagalan yang tepat untuk setiap percobaan, dan logsEnabled: true di konfigurasi plugin mencetak authorize URL dan token response di perangkat.

Menerbitkan update

Perubahan kebijakan di sisi Entra bersifat instan, tetapi perbaikan di sisi klien tetap harus sampai ke perangkat. Perubahan TypeScript seperti scopes atau penanganan error dapat dikirim melalui Live updates Capgo. Perubahan native (intent filters, skema baru) membutuhkan build store baru, yang Build Capgo dapat dihasilkan tanpa Mac lokal.

Live updates untuk aplikasi Capacitor

Saat bug web-layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna mendapat update di background, sementara perubahan native tetap mengikuti jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.