Native Android SDK for integrating SIROS ID wallet infrastructure into existing apps.
| Module | Description |
|---|---|
sdk:transport |
Transport-independent WMP client (WebSocket, HTTPS+SSE) |
sdk:auth |
WebAuthn/passkey authentication with PRF key derivation |
sdk:keystore |
JWE-encrypted keystore for credential signing keys |
sdk:flow |
OID4VCI/OID4VP flow orchestration over WMP |
sdk:credentials |
Credential storage and metadata |
sdk:passkey-provider |
Android Credential Provider Service for passkeys |
sample-app |
Minimal example wallet app |
┌─────────────────────────────────────────┐
│ Your Native App │
│ ┌───────────────────────────────────┐ │
│ │ SIROS SDK │ │
│ │ ┌─────────┐ ┌───────────────┐ │ │
│ │ │ Flow │ │ Credentials │ │ │
│ │ │ Client │ │ Store │ │ │
│ │ └────┬────┘ └───────────────┘ │ │
│ │ │ │ │
│ │ ┌────┴────┐ ┌───────────────┐ │ │
│ │ │ WMP │ │ Keystore │ │ │
│ │ │ Session │ │ (JWE/PRF) │ │ │
│ │ └────┬────┘ └───────────────┘ │ │
│ │ │ │ │
│ │ ┌────┴────────────────────────┐ │ │
│ │ │ Transport (WebSocket) │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Auth (Credential Manager) │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Passkey Provider Service │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
The SDK includes a full WMP implementation as an alternative to the legacy WebSocket engine protocol:
WmpPeer— JSON-RPC 2.0 dispatch with profile-based routingOpenID4xProfile— OID4VCI/OID4VP flow handling (sign, match, trust evaluation)WmpHttpSseTransport— HTTP+SSE transport for firewall-restricted environmentsWmpWebSocketTransport— WebSocket transport withwmp.v1subprotocol
Enable via WalletConfig(useWmpProtocol = true). Requires backend with WMP endpoint.
The SDK auto-discovers the engine WebSocket URL from /.well-known/wallet-configuration:
// Resolution order: explicit engineUrl > discovery > backendUrl
val config = WalletConfig(
backendUrl = "https://wallet.example.com",
// engineUrl = null → auto-discovered
)Debug builds expose a gear icon on the login screen for configuring:
- Backend URL, Tenant ID, Engine URL
- WMP protocol toggle
Controlled by SHOW_PRE_LOGIN_SETTINGS build config (true in debug, false in release).
SirosWallet runs the whole wallet for you (issuance, presentation, the engine
conversation). Hosts that already run those flows - a web-view wrapper around
the SIROS web wallet, an app with its own protocol client - use the modules
underneath directly: keystore, auth and credentials, without flow or the
facade. Both are supported; docs/TWO-APIS.md explains the
split and shows the low-level composition.
Wrapper apps that host the SIROS web wallet in a WebView advertise what they
can do natively through one versioned capability descriptor. Its vocabulary is
defined once in spec/bridge-capabilities.json
and generated into Kotlin (org.siros.sdk.transport.bridge), Swift and
TypeScript - see spec/README.md.
Every module is published as org.siros:siros-sdk-<module> with a BOM, on
each release tag, to Maven Central (from 0.14.0; GitHub Packages continues
in parallel). The SDK's native dependencies - siros-wscd-manager,
siros-dc-matcher, zk-cred-longfellow, zk-cred-vega, zk-cred-bbs - are
on Central as well, so mavenCentral() alone resolves everything; no
repository block and no token:
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}// app/build.gradle.kts
dependencies {
implementation(platform("org.siros:siros-sdk-bom:0.14.0"))
implementation("org.siros:siros-sdk-wallet") // the orchestrated API; pulls in every other module
// or, flow-free: siros-sdk-keystore, siros-sdk-auth, siros-sdk-credentials - see docs/TWO-APIS.md
// implementation("org.siros:siros-sdk-passkey-provider") // only if the app is also a passkey provider (API 34+)
}To consume from GitHub Packages instead (for example an unreleased build of a
native crate), add its repository with a read:packages token:
maven {
url = uri("https://maven.pkg.github.com/sirosfoundation/<repo>")
credentials {
username = providers.gradleProperty("gpr.user").orNull
password = providers.gradleProperty("gpr.key").orNull
}
}minSdk 28 (Android 9) is the SDK's floor - BiometricPrompt and
hardware-backed key attestation start there - and compileSdk must be 36 or
higher. Everything above 28 is gated at runtime, never assumed:
| feature | needs | otherwise |
|---|---|---|
| passkey login, credentials, presentation | 28 + Google Play Services | - |
| Digital Credentials API | 28 + a Play Services build with Credential Manager (in practice Android 14+) | picker never shows this wallet |
siros-sdk-passkey-provider (this app as a passkey provider) |
34 (CredentialProviderService) |
module is inert |
| USB CTAP2 security keys | 33 for the exported-receiver flags; works on 28+ | - |
user-auth-bound keys (setUserAuthenticationParameters) |
30 | falls back to the pre-30 API |
The DC API entry
Activity and the NFC HCE Service are declared by the SDK's own manifests and
merged into the app; the app keeps WalletSessionHolder pointed at its
unlocked wallet and calls SirosCredentialRegistry.refresh when it has
credentials (see the sample app's WalletViewModel). What the app must still
declare itself: the deep-link schemes it handles (openid-credential-offer,
openid4vp, mdoc-openid4vp, haip, haip-vp, haip-vci) plus its own
authorization-callback scheme, the permissions it uses (camera, Bluetooth,
NFC), and its passkey relying-party assets on the backend side.
The public API of every module is recorded in sdk/<module>/api/<module>.api
and checked by ./gradlew apiCheck in CI; an intended change is committed with
./gradlew apiDump and reviewed as a diff of that file.
To build against an unreleased checkout, ./gradlew publishToMavenLocal -PsdkVersion=<anything> installs the same artifacts into ~/.m2, resolvable
with mavenLocal().
// 1. Create transport and session
val transport = WmpWebSocketTransport("wss://wallet.example.com/wmp")
val session = WmpSession(transport)
// 2. Authenticate and create session
session.create(authToken = accessToken)
// 3. Set up flow client
val flowClient = FlowClient(session, keystore)
flowClient.start()
// 4. Observe flow events
flowClient.events().collect { event ->
when (event) {
is FlowEvent.Complete -> handleCredentialReceived(event.result)
is FlowEvent.Progress -> updateUI(event.step)
is FlowEvent.SignRequest -> { /* auto-handled or manual */ }
is FlowEvent.MatchRequest -> respondToMatch(event)
is FlowEvent.Error -> showError(event.message)
}
}
// 5. Start credential issuance
flowClient.startIssuance(OID4VCIFlowParams(credentialOfferUri = uri))./gradlew assemble./gradlew test- Android SDK 28+ (Android 9.0)
- JDK 17
- Kotlin 2.1+
API documentation is generated using Dokka.
# Generate HTML documentation
./gradlew dokkaGenerateBSD 2-Clause — see LICENSE.