상태
Package 상태는 구현 및 로컬 검증 완료입니다. Dart 및 Flutter 단위 테스트 suite가 통과했으며 PKCE, nonce 및 ID token 검증, guest capability, session expiry, storage contracts를 다룹니다. platform-channel paths와 실제 IdP round-trip을 검증하려면 여전히 device 또는 simulator가 필요합니다. 이 페이지는 구현된 동작을 설명하며 production-ready 상태임을 주장하지 않습니다.
Registry 상태: UNPUBLISHED. 이 SDK는 저장소 소스 checkout에서만 설치하고 외부 package registry를 사용하지 마세요.
설치
pubspec.yaml에 추가하고 flutter pub get을 실행하세요:
# pubspec.yaml
dependencies:
xid:
git:
url: https://github.com/StringKe/xid
path: sdk/flutter
ref: main플랫폼 설정
각 플랫폼에 콜백 URI 스킴을 등록하세요.
<!-- Android: AndroidManifest.xml (main Activity) -->
<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.myapp" android:host="auth" />
</intent-filter>
<!-- iOS: Info.plist -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array><string>com.example.myapp</string></array>
</dict>
</array>빠른 시작
import 'package:xid/xid.dart';
final client = XidClient();
// 1. Initialize (fetches OIDC discovery). offline_access is rejected until DPoP is implemented.
await client.configure(
const XidOptions(
issuer: 'https://xid.dev',
clientId: 'YOUR_CLIENT_ID',
redirectUri: 'com.example.myapp://auth/callback',
scopes: ['openid', 'profile', 'email'],
),
);
// 2. Sign in (opens system browser, PKCE S256)
final session = await client.signIn();
print(session.user.email);
// 3. Get the current unexpired access token. Expiry requires reauthorization.
final token = await client.getAccessToken();
// 4. Get the current unexpired session.
final current = await client.getSession();
// 5. Clear secure storage and optionally open end_session. No revoke request is sent.
await client.signOut();핵심 API
| 방법 | 설명 |
|---|---|
configure(XidOptions, {storageAdapter?}) |
SDK를 초기화하고 OIDC 디스커버리를 가져옵니다. 다른 모든 메서드보다 먼저 호출해야 합니다. |
signIn({}additionalParameters?, audience?}) |
PKCE S256 인증 URL로 시스템 브라우저를 엽니다. 코드를 교환하고 XidSession을 반환합니다. |
handleRedirect(String url) |
App Link 또는 사용자 정의 스킴 콜백을 처리합니다. signIn 내부에서 호출됩니다. 크로스 프로세스 리디렉션 복구 시 수동으로 호출하세요. |
getSession() |
현재 만료되지 않은 XidSession을 반환합니다. 만료된 로컬 state를 지운 뒤에는 null을 반환합니다. |
getAccessToken({}bool forceRefresh}) |
현재 만료되지 않은 access token을 반환합니다. forceRefresh: true는 session을 지우고 재인증을 요구합니다. |
signOut({}bool openLogoutUrl}) |
secure storage를 지우고 필요하면 시스템 브라우저에서 end_session_endpoint를 엽니다. revoke request는 전송하지 않습니다. |
setTokenStorage(TokenStorageAdapter) |
기본 SecureStorageAdapter(flutter_secure_storage)를 사용자 정의 구현으로 교체합니다. |
의존성
| 패키지 | 버전 | 목적 |
|---|---|---|
flutter_web_auth_2 |
^4.0.0 | 시스템 브라우저 인증 세션 및 콜백 수신 |
flutter_secure_storage |
^9.2.4 | 플랫폼 안전 저장소(Keychain / Keystore / DPAPI) |
crypto |
^3.0.3 | PKCE S256 challenge 계산을 위한 SHA-256 |
http |
^1.2.2 | discovery 및 token 엔드포인트용 HTTP 클라이언트 |
보안
- 공개 클라이언트 — client secret이 저장되거나 전송되지 않습니다.
- PKCE S256만 사용합니다. implicit 흐름과 password grant는 지원하지 않습니다.
- 요청마다 생성되는 OAuth state; CSRF를 방지하기 위해 handleRedirect에서 검증됩니다.
- 새 session은 access token과 ID token을 플랫폼 secure storage에 저장합니다. refreshToken compatibility field는 null로 유지되며 DPoP가 구현될 때까지 offline_access를 거부합니다.
알려진 제한 사항
- JWKS 기반 ES256 ID token 검증, nonce 검증, 저장된 state-keyed PKCE가 구현되어 로컬에서 테스트되었습니다. L4 지원을 선언하려면 실제 device 및 IdP 검증이 더 필요합니다.
- SDK가 DPoP sender binding을 구현할 때까지 offline_access를 거부합니다. access-token이 만료되면 다시 인증해야 합니다.