Getting Started

Getting Started

Install

Add the core SDK, plus the Compose helper if you use Compose Multiplatform:

implementation("io.github.androidpoet:passkeys:0.1.0")          // core SDK
implementation("io.github.androidpoet:passkeys-compose:0.1.0")  // rememberPasskeyClient() (Compose MP)

The artifacts are published to Maven Central under the io.github.androidpoet group.

Your first ceremony

Get options from your server

Your backend generates the WebAuthn options JSON — crucially, a fresh challenge. The SDK never invents a challenge; it only runs the device ceremony against the one you pass in.

Resolve the platform client

In Compose Multiplatform, rememberPasskeyClient() resolves the correct platform client and its UI anchor (the Activity, UIWindow, NSWindow, or HWND the system dialog attaches to).

val passkeys = rememberPasskeyClient()

Run create / authenticate

Both calls are suspend functions that return a PasskeyResult:

when (val result = passkeys.create(registrationOptionsJson)) {
    is PasskeyResult.Success -> sendToBackend(result.value.rawJson)
    is PasskeyResult.Failure -> handle(result.error.code, result.error.message)
}

Verify on your server

POST result.value.rawJson back to your backend and verify it with a maintained WebAuthn server library before you trust the credential. See Server Verification.

A passkey is bound to your domain, so each platform needs proof you own it. Before the ceremony will succeed on Android/iOS/macOS you must complete Domain Setup.

Run the sample

:sample:composeApp is one Compose Multiplatform app — the whole UI lives in commonMain. Supply your own domain via a -P flag:

./gradlew :sample:composeApp:installDebug -PpasskeysSampleRpId=your-domain.com   # Android
./gradlew :sample:composeApp:run -PpasskeysSampleRpId=your-domain.com            # macOS desktop

…or put it in local.properties (gitignored) so you don’t repeat it every build:

passkeysSampleRpId=your-domain.com
passkeysSampleBundleId=com.your.app

A browser demo lives in :sample:web.