---
title: Mobile (preview)
status: new
---

# Mobile SDKs (preview)

!!! warning "Preview"
    Native iOS/Android SDKs are scheduled for a future release. The flow below — system browser + PKCE — works today and is the recommended pattern.

## Native LXL SDKs (spec, in development)

The native SDK packages are spec-locked and live in their own repos. The
public surface is stable; the network-bound method bodies throw
`notImplemented` until v0.2.

| Platform | Package | Repo |
|---|---|---|
| iOS (Swift Package, iOS 15+) | `LXLId`                     | [`littlexlittle/id-mobile-ios`](https://github.com/littlexlittle/id-mobile-ios) |
| Android (AAR, minSdk 24)     | `org.littlexlittle:id`      | [`littlexlittle/id-mobile-android`](https://github.com/littlexlittle/id-mobile-android) |

Until those publish, use the **AppAuth-based recipe** below — it works
against the same discovery document and produces interoperable tokens.

## iOS (Swift) — using ASWebAuthenticationSession

```swift
import AuthenticationServices

let verifier = PKCE.generateVerifier()
let challenge = PKCE.codeChallenge(for: verifier)

var components = URLComponents(string: "https://id.littlexlittle.org/oidc/authorize")!
components.queryItems = [
  URLQueryItem(name: "response_type", value: "code"),
  URLQueryItem(name: "client_id", value: clientId),
  URLQueryItem(name: "redirect_uri", value: "com.yourorg.app://oauth/callback"),
  URLQueryItem(name: "scope", value: "openid profile email lxl.access"),
  URLQueryItem(name: "state", value: state),
  URLQueryItem(name: "nonce", value: nonce),
  URLQueryItem(name: "code_challenge", value: challenge),
  URLQueryItem(name: "code_challenge_method", value: "S256"),
]

let session = ASWebAuthenticationSession(
  url: components.url!,
  callbackURLScheme: "com.yourorg.app"
) { callbackURL, error in
  guard let url = callbackURL,
        let code = URLComponents(url: url, resolvingAgainstBaseURL: false)?
                       .queryItems?.first(where: { $0.name == "code" })?.value
  else { return }
  exchangeCode(code, verifier: verifier)
}
session.prefersEphemeralWebBrowserSession = false
session.presentationContextProvider = self
session.start()
```

## Android (Kotlin) — using Custom Tabs + AppAuth pattern

```kotlin
val verifier = generateCodeVerifier()
val challenge = generateCodeChallenge(verifier)

val authUri = Uri.parse("https://id.littlexlittle.org/oidc/authorize").buildUpon()
    .appendQueryParameter("response_type", "code")
    .appendQueryParameter("client_id", clientId)
    .appendQueryParameter("redirect_uri", "com.yourorg.app://oauth/callback")
    .appendQueryParameter("scope", "openid profile email lxl.access")
    .appendQueryParameter("state", state)
    .appendQueryParameter("nonce", nonce)
    .appendQueryParameter("code_challenge", challenge)
    .appendQueryParameter("code_challenge_method", "S256")
    .build()

CustomTabsIntent.Builder().build().launchUrl(this, authUri)
```

Handle the `com.yourorg.app://oauth/callback` deep link in your `AndroidManifest.xml` and exchange the code for tokens against `/oidc/token`.

## Redirect URI conventions

| Platform | Scheme |
|---|---|
| iOS / Android | Reverse-DNS app scheme: `com.yourorg.app://oauth/callback` |
| Universal Links / App Links | `https://yoursite.org/oauth/callback` (preferred — phishing-resistant) |
| Desktop (loopback) | `http://127.0.0.1:RANDOM_PORT/cb` (RFC 8252) |

Register all redirect URIs you'll use in the [developer portal](https://app.littlexlittle.org/developers).

## Recommended libraries

- **iOS:** [AppAuth-iOS](https://github.com/openid/AppAuth-iOS)
- **Android:** [AppAuth-Android](https://github.com/openid/AppAuth-Android)
- **Flutter:** [`flutter_appauth`](https://pub.dev/packages/flutter_appauth)
- **React Native:** [`react-native-app-auth`](https://github.com/FormidableLabs/react-native-app-auth)

All four libraries accept a discovery URL — point them at `https://id.littlexlittle.org/.well-known/openid-configuration` and they'll auto-configure.
