상태
패키지 상태: 구현됨 · 로컬 검증 완료. JVM 단위 테스트(24개 통과)가 PKCE 생성, OAuth state, 인메모리 저장소를 다룹니다. EncryptedSharedPreferences(Keystore AES-256-GCM), Chrome Custom Tabs, App Links 동작은 실제 Android 기기 또는 에뮬레이터가 필요합니다. 실제 IdP 왕복 테스트는 수동 검증 대기 중입니다. 이 페이지는 구현된 동작을 문서화하며, 프로덕션 준비 완료를 의미하지 않습니다.
요구 사항
- Android API 26 이상(Android 8.0)
- Kotlin 1.9 이상 및 AndroidX
설치
앱 모듈의 build.gradle.kts에 의존성을 추가하세요:
dependencies {
implementation("dev.xid:xid-android:0.1.0-alpha")
}
// Local development: add to settings.gradle.kts
includeBuild("../sdk/android")매니페스트 설정
intent-filter가 있는 콜백 Activity를 등록하세요. 사용자 정의 스킴보다 App Links(autoVerify가 있는 HTTPS 스킴)를 권장합니다:
<!-- AndroidManifest.xml -->
<activity android:name=".AuthCallbackActivity" android:exported="true">
<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="yourapp.example.com"
android:pathPrefix="/auth/callback" />
</intent-filter>
</activity>빠른 시작
import dev.xid.sdk.Xid
import dev.xid.sdk.model.XidConfig
// 1. Initialize in Application.onCreate
Xid.configure(
context = this,
config = XidConfig(
issuer = "https://xid.dev",
clientId = "your_client_id",
redirectUri = "https://yourapp.example.com/auth/callback",
scopes = listOf("openid", "profile", "email", "offline_access"),
)
)
// 2. Sign in (opens Chrome Custom Tabs)
lifecycleScope.launch { Xid.signIn(requireContext()) }
// 3. Handle redirect in AuthCallbackActivity
val session = Xid.handleRedirect(intent.data.toString())
// 4. Get current session (auto-refreshes near expiry)
val session = Xid.getSession()
// 5. Get access token
val token = Xid.getAccessToken()
// 6. Sign out
Xid.signOut(context = this, openEndSession = true)핵심 API
| 방법 | 서명 |
|---|---|
configure |
fun configure(context: Context, config: XidConfig) |
signIn |
suspend fun signIn(context: Context, options: SignInOptions? = null) |
handleRedirect |
suspend fun handleRedirect(url: String): XidSession |
getSession |
suspend fun getSession(): XidSession? |
getAccessToken |
suspend fun getAccessToken(options: GetAccessTokenOptions? = null): String |
signOut |
suspend fun signOut(context: Context? = null, openEndSession: Boolean = false) |
setTokenStorage |
fun setTokenStorage(adapter: TokenStorageAdapter) |
오류 타입
모든 SDK 오류는 봉인 클래스 XidException의 하위 타입입니다:
| 하위 클래스 | 트리거 |
|---|---|
NotConfigured |
configure()가 호출되지 않았습니다 |
UserCancelled |
사용자가 완료하지 않고 Custom Tabs를 닫았습니다 |
StateMismatch |
OAuth state 불일치 — CSRF 가능성이 있습니다 |
TokenExchangeFailed |
token 엔드포인트에서 오류가 반환되었습니다 |
TokenRefreshFailed |
refresh 토큰이 만료되었거나 폐기되었습니다 |
NoSession |
로그아웃 상태에서 세션 메서드가 호출되었습니다 |
보안
- 공개 클라이언트 — client secret이 저장되거나 전송되지 않습니다.
- PKCE S256만 사용합니다. 서버는 plain challenge 방식을 거부합니다.
- Android Keystore(AES-256-GCM) 기반의 EncryptedSharedPreferences가 저장된 토큰을 보호합니다.
- 요청마다 생성되는 무작위 OAuth state; CSRF를 방지하기 위해 리디렉션 시 검증됩니다.
알려진 제한 사항
- JWKS 기반 ID token 검증은 구현되어 로컬 단위 테스트를 통과했습니다. L4 지원 전에는 Android 기기 또는 emulator와 IdP 검증이 필요합니다.
- 사용자가 인증을 완료하지 않고 Custom Tabs를 닫는 경우를 감지하는 메커니즘이 없습니다.
- 단일 계정 전용 — 저장소 레이어는 고정 키를 사용합니다.