Android SDKs
The Android SDK lives in android-sdks, a Kotlin library split into a platform layer and a Compose component library.
src/main/kotlin/dev/thunderid/
android/ Core SDK
auth/ PKCE and flow execution
http/ HTTP client
token/ Token store, validator, refresher, JWKS cache
compose/ Jetpack Compose component library
components/
actions/ SignInButton, SignOutButton, SignUpButton
guards/ SignedIn, SignedOut, Loading
presentation/ SignIn, SignUp, user and organization components
i18n/ Localization
src/test/kotlin/ Unit tests
tests/e2e/ End-to-end suite
playground/ App for exercising the SDK from source
The layering runs core → Compose. The quickstart sample lives in quickstarts/android in the samples repository and depends on the published SDK. tests/e2e/scripts/prepare-sample.sh fetches it into tests/e2e/.samples and substitutes your checkout through includeBuild, so a change to the SDK is picked up when you rebuild that copy.
Every Compose component ships in two variants: a styled one with opinionated Material 3 defaults, such as SignInButton, and a base slot-based one for full customization, such as BaseSignInButton.
Commands
./gradlew build
./gradlew test
./gradlew lint ktlintCheck
Build and install the prepared sample onto a running emulator with ./gradlew installDebug from tests/e2e/.samples/quickstarts/android. That directory is its own Gradle build, so ktlintCheck does not exist there; run lint from the repository root.
Playground
playground/ is a Jetpack Compose app that substitutes the SDK from this checkout through includeBuild, so it always runs your changes. It has four tabs: capability checks for each SDK feature with a pass or fail reason, a component explorer with live controls and generated Compose code, a session inspector for tokens and claims, and an SDK event log. Copy config.properties.example to config.properties, fill in your server URL and application, then run ./gradlew installDebug from playground/ with an emulator running. The pull request builder lints and builds it, so keep its checks and stories in step when you change a capability or a component.
Code Style
- Kotlin targeting JVM 17.
minSdk26 for the SDK, 24 for the sample. - Jetpack Compose via BOM
2024.02.00. - No dependency injection framework. State reaches components through
CompositionLocal(LocalThunderID). - Coroutines (
suspendandFlow) rather than callbacks. - No third-party networking.
HttpClientwrapsHttpURLConnection. - Token storage uses
EncryptedSharedPreferencesbehind theStorageAdapterinterface. - Errors use the typed
IAMErrorCodeenum andIAMException.
ktlintCheck gates CI and every violation fails the build. The rules worth remembering are a 120-character line limit, alphabetically sorted imports with no wildcards, trailing commas on multi-line declarations but not at call sites, and } else { on one line.
Vendor Naming
The SDK is white-labelable through ThunderIDConfig.vendor. Do not hardcode thunderid in a runtime name that override should control, such as an EncryptedSharedPreferences key or a log tag. Resolve it from config.vendor instead.
An entry point whose purpose is to represent the SDK itself, such as ThunderIDClient, is a fixed identity and keeps the name.