Skip to content

sdk/flutter

Dart / Flutter SDK for iOS, Android, and desktop using flutter_web_auth_2, PKCE S256 authorization code flow, and flutter_secure_storage token persistence.

Status

Package status is Implemented · verified locally. Pure-Dart unit tests (21 passed) cover PKCE, token models, and in-memory storage. Platform-channel paths (flutter_secure_storage, flutter_web_auth_2) require a real device or simulator to verify. Real IdP round-trip is pending manual verification. This page documents implemented behavior; it is not a production-readiness claim.

Installation

Add to pubspec.yaml and run flutter pub get:

# pubspec.yaml
dependencies:
  xid:
    git:
      url: https://github.com/StringKe/xid
      path: sdk/flutter
      ref: main

Platform setup

Register the callback URI scheme on each platform.

<!-- 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>

Quick start

import 'package:xid/xid.dart';

final client = XidClient();

// 1. Initialize (fetches OIDC discovery)
await client.configure(
  const XidOptions(
    issuer: 'https://xid.dev',
    clientId: 'YOUR_CLIENT_ID',
    redirectUri: 'com.example.myapp://auth/callback',
    scopes: ['openid', 'profile', 'email', 'offline_access'],
  ),
);

// 2. Sign in (opens system browser, PKCE S256)
final session = await client.signIn();
print(session.user.email);

// 3. Get valid access token (auto-refreshes)
final token = await client.getAccessToken();

// 4. Get current session
final current = await client.getSession();

// 5. Sign out (revokes refresh token + clears secure storage)
await client.signOut();

Core API

Method Description
configure(XidOptions, {storageAdapter?}) Initialize SDK and fetch OIDC discovery. Must be called before all other methods.
signIn({}additionalParameters?, audience?}) Open system browser with PKCE S256 authorization URL; exchange code and return XidSession.
handleRedirect(String url) Process App Link or custom scheme callback. Called internally by signIn; invoke manually for cross-process redirect recovery.
getSession() Return XidSession? — triggers refresh token rotation if access token is near expiry (within 60 s).
getAccessToken({}bool forceRefresh}) Return a valid access token string. Pass forceRefresh: true to force renewal.
signOut({}bool openLogoutUrl}) Revoke refresh token (RFC 7009), clear secure storage, and optionally open end_session_endpoint in the browser.
setTokenStorage(TokenStorageAdapter) Replace the default SecureStorageAdapter (flutter_secure_storage) with a custom implementation.

Dependencies

Package Version Purpose
flutter_web_auth_2 ^4.0.0 System browser authorization session and callback receipt
flutter_secure_storage ^9.2.4 Platform secure storage (Keychain / Keystore / DPAPI)
crypto ^3.0.3 SHA-256 for PKCE S256 challenge computation
http ^1.2.2 HTTP client for discovery and token endpoints

Security

  • Public client — no client secret stored or transmitted.
  • PKCE S256 only. No implicit flow or password grant.
  • OAuth state generated per request; validated in handleRedirect to prevent CSRF.
  • Refresh tokens are stored in platform secure storage (Keychain on iOS, Keystore on Android) and rotated on every use by the XID server.

Known limitations

  • JWKS-backed ES256 ID token verification, persisted state-keyed PKCE, and refresh single-flight are implemented and locally tested. Real device and IdP validation are still required before L4 support.
  • offline_access must be included in scopes to receive a refresh token.
Navigation

Type to search...

Use arrow keys to navigateEnter to selectEscape to close