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
- Buka Pusat admin Microsoft Entra dan buka Entra ID > App registrations > New registration.
- Masukkan nama, misalnya “Example Mobile”.
- Pilih Jenis akun yang didukung. Ini menentukan authority yang Anda gunakan nanti.
- Lewati redirect URI dulu dan klik Daftar.
- 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/azuresebagai URI redirect kustom. Tambahkancom.example.app://oauth/logoutjuga 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:
- Buka Ekspos API dan atur Application ID URI, biasanya
api://<client-id>. - Tambahkan scope bernama
access_as_user, who can consent: Admins and users. - Di Manifest, setel
"requestedAccessTokenVersion": 2sehingga 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.