@team-lepisode/capacitor-apple-login
v8.0.2
Published
Capacitor plugin for Apple Login
Readme
@team-lepisode/capacitor-apple-login
iOS와 Android에서 Sign in with Apple을 사용할 수 있는 Capacitor 플러그인입니다.
iOS에서는 Apple의 네이티브 AuthenticationServices 흐름을 사용합니다. Android에서는 Apple OAuth를 브라우저로 시작하고, Apple이 요구하는 HTTPS 백엔드 콜백에서 토큰 교환을 끝낸 뒤 앱에는 짧은 수명의 handoff token만 돌려줍니다.
Apple OAuth 전략과 현재 동작
현재 플러그인 동작은 Apple OAuth 제약에 맞습니다.
- iOS: 앱 entitlement와 bundle 설정을 사용하는
ASAuthorizationAppleIDProvider기반 네이티브 로그인입니다.clientId,redirectURI,callbackURI는 iOS에서 사용하지 않습니다. - Android:
https://appleid.apple.com/auth/authorize를 AppAuth 브라우저 흐름으로 엽니다. - Android:
email또는namescope가 있으면response_mode=form_post를 사용합니다. Apple의 form post 응답은 앱 커스텀 스킴으로 직접 받을 수 없으므로,redirectURI는 Apple에 등록된 공개 HTTPS 백엔드 콜백이어야 합니다. - Android: 백엔드는 Apple code와 identity token을 검증/교환하고, 앱으로는 검증된 Android App Link(
callbackURI)에handoff_token과state만 붙여 리다이렉트해야 합니다. - Android: 플러그인은 callback URI,
state,handoff_token을 확인한 뒤{ platform: 'android', handoffToken, state }를 반환합니다. Apple code나 identity token을 Android 앱에 직접 반환하지 않습니다.
설치
npm install @team-lepisode/capacitor-apple-login
npx cap synciOS 설정
사용하는 앱 타깃에서 Sign in with Apple capability를 켜고 Apple Developer portal에도 동일하게 설정합니다.
iOS 구현은 AuthenticationServices를 사용합니다. Apple이 앱 entitlement와 bundle 설정을 사용하므로 iOS에서는 clientId, redirectURI, callbackURI 옵션이 무시됩니다.
import { CapacitorAppleLogin } from '@team-lepisode/capacitor-apple-login';
const result = await CapacitorAppleLogin.authorize({
scopes: ['email', 'name'],
state: 'opaque-state',
nonce: 'opaque-nonce',
});
// result.authorizationCode, result.identityToken, result.user 등을 백엔드로 보내 검증합니다.Android 설정
Apple Developer portal에서 Sign in with Apple Services ID를 만들고, 공개 HTTPS 백엔드 콜백을 Apple redirect URI로 등록합니다.
scope를 요청하면 Apple은 인증 결과를 form_post로 보냅니다. Android 앱은 이 POST를 직접 받을 수 없으므로 백엔드가 Apple 콜백을 받아 code 교환, identity token 검증, 사용자 세션 생성을 위한 handoff token 발급을 처리해야 합니다.
앱으로 돌아오는 URL은 검증된 Android App Link여야 합니다. consuming app의 manifest에서 AppAuth receiver를 다음처럼 설정합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity
android:name="net.openid.appauth.RedirectUriReceiverActivity"
android:exported="true"
tools:node="replace">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="app.example.com"
android:path="/apple-login" />
</intent-filter>
</activity>
</application>
</manifest>백엔드에서 인증 트랜잭션 값을 받은 뒤 authorize()를 호출합니다.
import { CapacitorAppleLogin } from '@team-lepisode/capacitor-apple-login';
const options = await fetch('https://api.example.com/auth/apple/start', {
method: 'POST',
credentials: 'include',
}).then((response) => response.json());
const { handoffToken } = await CapacitorAppleLogin.authorize(options);
await fetch('https://api.example.com/auth/apple/complete', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ handoffToken }),
});백엔드 start 응답은 다음 값을 제공해야 합니다.
{
"clientId": "com.example.service",
"redirectURI": "https://api.example.com/auth/apple/callback",
"callbackURI": "https://app.example.com/apple-login",
"scopes": ["email", "name"],
"state": "backend-generated-state",
"nonce": "backend-generated-nonce"
}clientId: Apple Services ID입니다.redirectURI: Apple에 등록된 공개 HTTPS 백엔드 콜백입니다.callbackURI: 백엔드가 앱으로 돌려보낼 검증된 Android App Link입니다.state,nonce: 백엔드가 생성하고 저장한 일회성 값이어야 합니다.- 커스텀 스킴 redirect URI, localhost, IP 주소, fragment가 있는 URI는 Android에서 거부됩니다.
자세한 백엔드 계약, callback 의사 코드, token 처리 요구사항, Digital Asset Links 설정은 Android backend flow를 참고하세요.
Apple은 이름과 이메일을 보통 최초 승인 시점에만 제공합니다. 백엔드 콜백에서 값을 검증하고 필요한 경우 저장하세요.
API
authorize(...)
authorize(options?: AppleLoginOptions | undefined) => Promise<AppleLoginResult>Starts Sign in with Apple.
On iOS this uses AuthenticationServices. On Android this uses Apple's
browser-based OAuth flow and requires clientId, redirectURI,
callbackURI, state, and nonce from a backend authorization
transaction.
| Param | Type |
| ------------- | --------------------------------------------------------------- |
| options | AppleLoginOptions |
Returns: Promise<AppleLoginResult>
isAvailable()
isAvailable() => Promise<{ available: boolean; }>Returns whether Apple login is available on the current platform.
Returns: Promise<{ available: boolean; }>
getCredentialState(...)
getCredentialState(options: { user: string; }) => Promise<{ state: AppleCredentialState; }>Gets the credential state for an Apple user identifier.
Supported on iOS only.
| Param | Type |
| ------------- | ------------------------------ |
| options | { user: string; } |
Returns: Promise<{ state: AppleCredentialState; }>
Interfaces
AppleLoginResult
| Prop | Type | Description |
| ----------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| handoffToken | string | Short-lived, single-use backend handoff token. Returned on Android and redeemable only at your backend for an application session. |
| authorizationCode | string | Returned by the native AuthenticationServices flow on iOS. |
| identityToken | string | Returned by the native AuthenticationServices flow on iOS. |
| user | string | |
| email | string | |
| givenName | string | |
| familyName | string | |
| state | string | |
| nonce | string | |
| realUserStatus | AppleRealUserStatus | |
| platform | 'ios' | 'android' | |
AppleLoginOptions
| Prop | Type | Description |
| ----------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| clientId | string | Apple Services ID. Required on Android and normally supplied by your backend's authorization-start endpoint. |
| redirectURI | string | Public HTTPS backend callback registered with Apple. Required on Android. Apple sends its form_post response to this URI. |
| callbackURI | string | Verified HTTPS Android App Link used by the backend to return control to the app. Required on Android. |
| scopes | AppleLoginScope[] | Requested Apple scopes. Defaults to ['email', 'name']. |
| state | string | Opaque state value passed through Apple authorization. On Android this is required and must be created by your backend authorization transaction. |
| nonce | string | Opaque nonce value passed through Apple authorization. On Android this is required and must be created by your backend authorization transaction. |
Type Aliases
AppleRealUserStatus
'unsupported' | 'unknown' | 'likelyReal'
AppleLoginScope
'email' | 'name'
AppleCredentialState
'authorized' | 'revoked' | 'notFound' | 'transferred' | 'unsupported'
