Microsoft Entra ID (Azure AD)를 사용하여 Capacitor 앱에 로그인하려면 Entra 관리 센터에서 공용 클라이언트 앱을 등록하고 리다이렉트 URI를 추가하여 로그인 기능을 활성화하세요. 모바일 및 데스크톱 애플리케이션 리다이렉트 URI와 같은 com.example.app://oauth/azure그리고 시스템 브라우저를 통해 OpenID Connect 인증 code 흐름을 PKCE로 실행하세요. @capgo/capacitor-social-login 그것은 Microsoft identity platform v2.0 엔드포인트와 하나의 initialize Microsoft identity platform v2.0 엔드포인트와의 호출 SocialLogin.login({ provider: 'oauth2', options: { providerId: 'azure' } }).
This guide covers the app registration, choosing the right authority, Graph and custom API scopes, token validation, Conditional Access, logout, and the AADSTS errors you will see. It targets Capacitor 8 in October 2026.
Microsoft Entra 테넌트와 앱 등록을 만들 수 있는 역할 (Application Developer 또는 상위 역할)
- __CAPGO_KEEP_0__ 8 앱과
- Capacitor 8 앱과 그
appId선택적으로, Entra 토큰을 수락하는 백엔드 __CAPGO_KEEP_0__가 필요합니다. - Optional backend API that accepts Entra tokens.
MSAL.js를 WebView 내부에 넣지 말라
MSAL.js는 브라우저의 원본을 소유하고 팝업을 열 수 있는 브라우저에만 구축되었습니다. Capacitor WebView에서 원본은 capacitor://localhost Android에서 https://localhost 안드로이드에서 팝업은 차단되고, 전체 페이지 리다이렉트는 앱을 자신의 번들에서 벗어나게 합니다. Microsoft의 네이티브 앱에 대한 지침은 PKCE (RFC 8252)를 사용하는 시스템 브라우저입니다. 이 플러그인은 이와 같습니다:
| 플랫폼 | 사용하는 브라우저 | 추가 설정 |
|---|---|---|
| iOS | ASWebAuthenticationSession |
없음 |
| 안드로이드 | Chrome Custom Tabs와 함께 androidUseCustomTabs: true |
인텐트 필터 |
| 웹 | 팝업 또는 리다이렉트 | SPA 리다이렉트 URI |
On Android, Custom Tabs를 켜세요. 기본으로 제공되는 WebView는 Microsoft Authenticator, passkeys 또는 Company Portal과 대화할 수 없으며, Conditional Access는 종종 이러한 요소에 의존합니다.
Step 1: Entra ID에 앱을 등록하세요.
- 열기 Microsoft Entra 관리 센터 그리고 이동하세요 이름을 입력하세요. 예를 들어 "Example Mobile"..
- 지원되는 계정 유형을 선택하세요.
- 이미지 이미지Register
- Register Register.
- On Overview, 복사하여 애플리케이션 (클라이언트) ID 및 디렉터리(테넌트) ID.
권한 선택
| 등록 시 계정 유형 | URL의 권한 구분 |
|---|---|
| 단일 테넌트 (당사만) | 예를 들어, 테넌트 ID 8f1c... |
| 어떤 조직 디렉토리 | organizations |
| 어떤 조직 디렉터리와 개인 Microsoft 계정 | common |
| 개인 Microsoft 계정만 | consumers |
tenant ID를 사용할 수 있는 경우에는 항상 tenant ID를 사용하세요. tenant ID를 사용하면 예측 가능한 issuer를 생성하고 다른 tenant에서 의도치 않은 로그인 방지를 할 수 있습니다.
redirect URI 추가
가장 인증 > 플랫폼 추가:
- 모바일 및 데스크톱 애플리케이션: 추가
com.example.app://oauth/azure사용자 지정 redirect URI로 추가합니다. post-logout redirect를 원한다면com.example.app://oauth/logout단일 페이지 애플리케이션 - (웹 빌드만 배송하는 경우): 추가 Any org directory plus personal Microsoft accounts
https://app.example.com/auth/callback.
등록하지 마세요. 모바일 URI 웹웹 플랫폼 리다이렉션은 비밀을 요구하는 신뢰할 수 있는 클라이언트입니다.
API 권한
API 권한 이미 포함되어 있습니다. Microsoft Graph > User.Read추가 offline_access, openid, profile 그리고 email 그들이 목록에 나열되지 않은 경우. 일부 테넌트는 사용자 동의를 차단합니다. 그 경우 관리자는 클릭해야 합니다. 관리자 동의 승인그렇지 않으면 사용자는 AADSTS65001 또는 "관리자 승인 필요" 화면을 볼 것입니다.
자신의 API (선택 사항) 에 대한 범위 노출
백엔드가 토큰을 수락해야 하는 경우:
- 열기 API을 공개하고 일반적으로
api://<client-id>. - 이름이 지정된 범위 추가:
access_as_userconsent를 제공할 수 있는 사용자: - 관리자 및 사용자. InManifest
"requestedAccessTokenVersion": 2,
액세스 토큰이 v2.0 발급자 형식으로 사용되도록 설정합니다.
bun add @capgo/capacitor-social-login
bunx cap sync
관리자 및 사용자. android/app/src/main/AndroidManifest.xml, inside 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>
Keep android:launchMode="singleTask" on MainActivity (기본값인 Capacitor을-사용합니다. Google, Apple 또는 Facebook 로그인을-사용하지 않으면, 그들을 plugins.SocialLogin.providers in capacitor.config.ts 사용하여-SDK를-빌드에서-제거합니다.
Step 3: 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,
},
},
});
}
context resourceUrl Page/area: About Capgo page. Role: UI label. Seen in: page about.astro. Message key `about_how_step_label` (About How Step Label). /meWith resourceData.
Graph를-포인트하고-있는 경우, 플러그인은 로그인 직후 Graph를-호출하고 프로필을 SocialLoginAuthConnect has an azure 기본 설정만 필요합니다. tenantId, clientId 및 redirectUrl. 보시면 4단계: 로그인.
유용한 옵션:
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;
}
}
계정과 사용자를 미리 채워두고 계정 선택기에서 사용자를 건너뜁니다.
loginHint: 'jane@contoso.com'계정 선택기를 항상 표시하여 공유 장치에 유용합니다.prompt: 'select_account'사용자를 직접 연관된 IDP로 보냅니다.additionalParameters: { domain_hint: 'contoso.com' }계정에 이메일이 없는 경우 자주 사용됩니다.
mail 또는 null 계정에 이메일이 없는 경우 userPrincipalName or the preferred_username ID 토큰의 주장.
5단계: 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();
}
5단계: Microsoft Graph를 호출합니다. Calendars.Read) 둘 다 API 권한 그리고 그것을 scope 그리고
API 권한
6단계: __CAPGO_KEEP_0__에 대한 토큰을 가져옵니다. azure same place oauth2 map of your initialize 인증 요청을 하시면 API 범위 대신 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,
},
},
});
사용자는 이미 Microsoft 세션을 가지고 있으므로 두 번째 로그인은 일반적으로 프롬프트 없이 완료됩니다. 서버에서 토큰을 검증하십시오:
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
}
다중 테넌트 앱의 경우 발급자에는 고객의 테넌트 ID가 포함되어 있습니다. 검증할 대신에 수락하는 테넌트 목록에 클레임을 검증하십시오. tid claim을 검증할 때는 고정된 발급자 대신 수락하는 테넌트 목록을 사용하십시오. Key 사용자는 이메일 대신 플러스에 있습니다. oid plus tidEntra의 공개 클라이언트 refresh 토큰은 90일 이내에 유효하며 슬라이딩 윈도우로 교체되며 각 사용 시 새로운 토큰이 저장됩니다. 플러그인은 새로운 토큰을 저장합니다. 토큰을 저장하는 경우 Keychain 또는 Keystore를 사용하십시오.
예를 들어 @__CAPGO_KEEP_0__/__CAPGO_KEEP_1__-native-biometric에서 토큰을 가져와서
// 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' });
local 토큰을 삭제하고 시스템 브라우저에서 v2.0 로그아웃 엔드포인트를 열어 주십시오. Microsoft는 종종 사용자가 로그아웃한 후 사용자 계정에 대한 '계정에서 로그아웃' 페이지를 표시하므로 사용자는 종종 이를 닫아 주어야 합니다. 로컬 로그아웃만 필요하다면 NativeBiometric.setData from @capgo/capacitor-native-biometric@__CAPGO_KEEP_0__ SocialLogin.refreshToken.
logout @__CAPGO_KEEP_1__ logoutUrl native-biometric prompt: 'select_account' 다음 로그인 시.
조건부 액세스 및 인튜브
브라우저 기반 OIDC는 MFA, 비번리스 및 대부분의 조건부 액세스 정책과 함께 작동합니다. 두 가지 경우가 더 필요합니다.
- 관리되지 않은 장치에 대한 요구: 엔트라가 장치 상태를 볼 수 있어야 합니다. 안드로이드에서는 회사 포털 또는 인증자 설치 시 Custom Tabs를 통해 작동합니다. 관리되는 iOS 장치에서, Microsoft Enterprise SSO 플러그인을 배포한 MDM은 이를 제공합니다. 실제 정책으로 테스트하세요.
- 인튜브 앱 보호 정책 (MAM): 이 정책은 인튜브 앱 SDK 내부에 있는 native 앱에서만 작동합니다. OIDC만으로는 '앱 보호 정책'을 요구하는 권한을 충족하지 못합니다.
문제 해결
| 오류 | 의미 | 수정 |
|---|---|---|
| AADSTS50011 | URI 재지정 오류 | 모바일 및 데스크톱 애플리케이션 아래에 정확한 URI를 추가하세요 |
| AADSTS7000218 | 토큰 요청이 비밀번호가 필요합니다 | Redirect가 Web에서 등록되어 있습니다. Mobile 및 데스크톱으로 이동하세요 |
| AADSTS9002326 | SPA에서만 허용되는 교차 출처 토큰 환원 오류 | 웹 빌드는 모바일 Redirect를 사용합니다. Single-page application 아래에 웹 URL을 등록하세요 |
| AADSTS700016 | 디렉터리에서 앱이 없습니다 | 권한의 tenant가 잘못되거나, 단일-tenant 앱을 사용하여 common |
| AADSTS50020 | 다른 테넌트의 사용자 계정 | 다중 테넌트 등록을 사용하거나 사용자를 초대하여 게스트로 사용 |
| AADSTS65001 | 동의가 부여되지 않았습니다 | 관리자 동의를 부여하거나 사용자 동의를 허용 |
| AADSTS53003 | 조건부 액세스에 의해 차단 | 로그인 로그를 확인하십시오, 위의 섹션을 참조하십시오 |
| AADSTS28000 | 한 번에 여러 리소스에 대한 범위가 여러 개일 때 | Graph 및 API 범위에 대한 별도의 로그인 요청 |
| 리프레시 토큰이 없습니다 | offline_access missing |
권한 범위와 허용에 추가하세요 |
Entra 관리 센터 로그인 로그 각 시도에 대한 정확한 실패 사유를 표시하고 logsEnabled: true 기기에서 plugin config에서 인증 URL 및 토큰 응답을 출력합니다.
배송 업데이트
Entra 측에서 정책 변경은 즉시 반영되지만 클라이언트 측 수정은 장치에 도달하기까지 시간이 걸립니다. TypeScript 변경 사항, 예를 들어 범위 또는 오류 처리는 Capgo Live Update. Capgo 빌드 __CAPGO_KEEP_0__ Build