API reference
Types, data models, and enums in the SenseCrypt Mobile SDK — the SenseCryptAuthenticator handle, flow surfaces, and every payload struct.
Naming follows each platform's convention: lowerCamelCase enum cases in Swift, UPPER_SNAKE_CASE in Kotlin, and property-style accessors on Android where Swift uses computed properties. The shapes are otherwise identical.
Entry point
public enum SenseCryptAuthn {
public static func open(config: AuthenticatorConfig, appGroupIdentifier: String? = nil) throws -> SenseCryptAuthenticator
}object SenseCryptAuthenticatorSDK {
fun open(
context: Context,
config: AuthenticatorConfig,
scanTheme: Int = /* default */,
playIntegrityCloudProjectNumber: Long = /* default */,
): SenseCryptAuthenticator
}SenseCryptAuthenticator
The handle you keep for the process lifetime.
| Member | Swift | Kotlin | Notes |
|---|---|---|---|
| Usable keys | keys: [Key] | keys: List<Key> | Filtered to keys with live hardware material. |
| Current key | currentKey: Key? | currentKey: Key? | |
| Branding lookup | brandingFor(keyId:) -> Branding? | brandingFor(keyId): Branding? | nil → fall back to a default icon. |
| Audit log | auditLog(limit:) -> [AuditEntry] | auditLog(limit): List<AuditEntry> | limit defaults to 50. |
| Start registration | startRegistrationFlow(email:clientId:sessionId:) throws | startRegistrationFlow(email, clientId, sessionId, systemPasskeyMode = false) | Throws AuthnInitError. |
| Start login | startLoginFlow() -> LoginFlow | startLoginFlow(): LoginFlow | Does not throw. |
| Start in-app sign-in | startSignInFlow(config:) -> SignInFlow, startSignInFlow(config:clientAssertionProvider:) | startSignInFlow(config): SignInFlow, startSignInFlow(config, clientAssertionProvider) | Does not throw. In-app sign-in; the second form is for a confidential client. |
| Signed-in session | currentSession() -> TokenSession?, signOut() | currentSession(): TokenSession?, signOut(), dpopInterceptor(): okhttp3.Interceptor | The in-app sign-in's stored DPoP-bound session, refreshed with its refresh token when the sign-in asked for offline_access. signOut() also revokes that refresh token at the IdP. iOS calls APIs through SenseCryptDPoP.data(for:). |
| Client-assertion provider | setClientAssertionProvider(_:), clearClientAssertionProvider() | setClientAssertionProvider(provider), clearClientAssertionProvider() | A confidential (private_key_jwt) client registers its provider once at launch, so the stored session's refresh and signOut()'s revocation can authenticate after a cold start. A public client never needs it. |
| Start PKI ceremony | startPkiCeremonyFlow() -> PkiCeremonyFlow | startPkiCeremonyFlow(): PkiCeremonyFlow | Does not throw. Face-PKI tenants only. |
| Start face report | startFaceReportFlow(rpId:clientDataHashB64url:credentialIdB64url:) -> FaceReportFlow | startFaceReportFlow(rpId, clientDataHashB64url, credentialIdB64url): FaceReportFlow | Does not throw. The personhood half of a passkey sign-in. Swift also takes the raw Data the OS hands an extension. |
| Pending face report | — | startPendingFaceReportFlow(): FaceReportFlow | Android 9–13 system-passkey path: adopts the newest parked assertion. |
| Sign an assertion | signAssertion(rpId:clientDataHashB64url:credentialIdB64url:) throws -> WebAuthnAssertion | signAssertion(rpId, clientDataHashB64url, credentialIdB64url): WebAuthnAssertion | Synchronous and offline. Swift also takes raw Data. |
| Passkey identities | passkeyIdentities() -> [PasskeyIdentity], publishPasskeyIdentities() async -> Int, clearPublishedPasskeyIdentities() async | passkeyIdentities(): List<PasskeyIdentity>, passkeyIdentitiesFor(rpId) | iOS publishes to the OS store; Android answers the provider service live. |
| Cross-device ceremony | — (the OS owns it on iOS) | parseHybridQr(qrUrl): HybridQrInfo, hasHybridPasskey(): Boolean, startHybridCeremonyFlow(qrUrl): HybridCeremonyFlow | Android only. parseHybridQr and startHybridCeremonyFlow throw HybridException. |
| Tenant apps | tenantApps(keyId:) -> [TenantApp] | tenantApps(keyId): List<TenantApp> | The apps of the key's tenant, from the local branding cache. |
| Branding sync | syncBranding(listener:includeBranding:) | syncBranding(listener, includeBranding) | Refreshes cached branding and the device's app list, and confirms to the server which accounts live on this phone; reports a summary to the listener. Call it on every app foreground (why). |
| Start revocation | startRevocationFlow(keyId:) throws | startRevocationFlow(keyId) | |
| Start rotation | startKeyRotationFlow() throws | startKeyRotationFlow() | Throws NoKeys when empty. |
| Rotation hint | takeKeyRotationHint() -> Bool | takeKeyRotationHint(): Boolean | One-shot; reading clears it. |
| Stage push token | updatePushToken(token:platform:) | updatePushToken(token, platform) | Fire-and-forget. |
| Upload push token | syncPushToken() | syncPushToken() | Fire-and-forget. |
| Load models | initializeInferenceEngine() async throws | initializeInferenceEngine(context) — suspend | Idempotent. |
Flow surfaces
Observation differs by platform and by flow. Login, registration, PKI ceremonies and the face report are hot streams; rotation and revocation hold state.
| Flow | Swift observation | Kotlin observation |
|---|---|---|
LoginFlow | stateStream(): AsyncStream<LoginState> | state: SharedFlow<LoginState> |
SignInFlow | stateStream(): AsyncStream<SignInState> | state: SharedFlow<SignInState> |
RegistrationFlow | stateStream(): AsyncStream<RegistrationState> | state: SharedFlow<RegistrationState> |
PkiCeremonyFlow | stateStream(): AsyncStream<PkiCeremonyState> | state: SharedFlow<PkiCeremonyState> |
FaceReportFlow | stateStream(): AsyncStream<FaceReportState> | state: SharedFlow<FaceReportState> |
HybridCeremonyFlow | — | subscribe(listener) and currentState() on the flow object |
FaceCaptureDriver | captureStateStream(): AsyncStream<FaceCaptureUiState> | state: SharedFlow<FaceCaptureUiState> |
RevocationFlow | stateStream(): AsyncStream<RevocationState> | state: StateFlow<RevocationState> |
KeyRotationFlow | stateStream(): AsyncStream<KeyRotationState> | state: StateFlow<KeyRotationState> |
On Android, LoginFlow, SignInFlow, RegistrationFlow, PkiCeremonyFlow, FaceReportFlow, and FaceCaptureDriver expose a SharedFlow, so there is no .value. Use the currentState property for a synchronous read. Only RevocationFlow and KeyRotationFlow are StateFlows.
Swift's stateStream() yields the current state first, then transitions — so a collector never has to wait for the next change to learn where it is.
LoginFlow
| Member | Purpose |
|---|---|
submitLinkPayload(payload:) | Feed the sign-in link bytes, from a scanned QR or a pushed universal link. Returns immediately. |
submitPassword(password:) | Only valid during downloadingFaceToken with passwordRequired. |
submitFaceCapture(captureSession:) | Submit a passing capture. Prefer the driver for portability. |
faceCaptureDriver() | Vend the capture driver. |
retryPostResult() | Re-send the cached proof after postingResultFailed. |
resetToScan() | Return to awaitingLink, clearing lastError. |
loginQrPng() | PNG bytes of this session's universal-link QR, or nil. |
cancel() | Local-only cancel; no server notification. |
cancelLogin() | Signed abort with user_cancelled, then terminal. Idempotent. |
id() | Flow identifier (Swift only). |
currentState() | Synchronous state read. |
SignInFlow
Signs the user in to your own app and stores DPoP-bound tokens. See In-app sign-in.
| Member | Purpose |
|---|---|
faceCaptureDriver() | Vend the capture driver. |
submitFaceCapture(captureSession:) | Submit a passing capture. Prefer the driver for portability. |
retry() | Re-send the captured proof after postingResultFailed, then exchange the code. Never re-captures. |
cancel() | Ends failed(.cancelled); aborts the IdP session in the background if one is open. |
currentState() / currentState | Synchronous state read. |
PkiCeremonyFlow
Answers a face-PKI ceremony. Result is delivered to the application, never to your app. See Face PKI.
| Member | Purpose |
|---|---|
submitLinkPayload(payload:) | Feed the pushed link bytes. Returns immediately. |
submitPassword(password:) | Only valid during downloadingFaceToken with passwordRequired. |
submitFaceCapture(captureSession:) | Submit a passing capture. Prefer the driver for portability. |
faceCaptureDriver() | Vend the capture driver. |
retry() | Re-send after deliveryFailed, or re-post /complete after postingResultFailed. Never re-captures. |
cancel() | Local-only cancel; no server notification. |
cancelCeremony() | Signed /abort (user_cancelled, or delivery_failed after a failed delivery), then terminal. |
currentState | Synchronous state read (Kotlin property). |
subscribe(listener:), id() | Listener-style observation and the flow identifier (Swift only; Kotlin observes state). |
FaceReportFlow
Proves the person after a passkey assertion has been parked. See Passkeys and the face report.
| Member | Purpose |
|---|---|
submitPassword(password:) | Only valid during downloadingFaceToken with passwordRequired. |
submitFaceCapture(captureSession:) | Submit a passing capture. Prefer the driver for portability. |
faceCaptureDriver() | Vend the capture driver. |
retryPostResult() | Re-send the report after postingResultFailed. |
cancel() | Tears down locally and, once the ceremony is resolved, files a best-effort user_cancelled report. |
ceremony() | The rpId and clientDataHashB64url in effect, or nil before a pending flow has adopted one. |
currentState | Synchronous state read. |
HybridCeremonyFlow (Android)
Runs the cross-device passkey ceremony for a scanned FIDO:/ code. See Passkeys and the face report.
| Member | Purpose |
|---|---|
selectAccount(credentialIdB64url) | Answer chooseAccount with the account to sign as. |
dismissAccountChoice() | Leave chooseAccount without signing. |
retry() | Re-run from the same scanned code with a fresh tunnel. |
cancel() | End the ceremony. |
subscribe(listener), currentState() | Observation. |
RegistrationFlow
| Member | Purpose |
|---|---|
submitPin(pin:) | Submit the emailed PIN. |
resendPin() | Request a new PIN. Respect cooldownUntil. After a first step that got no answer, runs that first step again. |
retryPostResult() | Re-send the cached completion after postingResultFailed, on either branch. |
submitSignupAttributes(values:address:consentAccepted:) | Signup branch form submission. |
faceCaptureDriver() | Vend the capture driver (signup branch). |
submitSystemPasskeyResponse(registrationResponseJson) | Android 9–13 with systemPasskeyMode: the Credential Manager createCredential() response. |
declineSystemPasskey() | Android 9–13 with systemPasskeyMode: the user backed out of the system passkey. |
cancel() | Abandon. |
currentState() | Synchronous state read. |
iOS additionally exposes submitFaceCapture(captureSession:) and id() directly on RegistrationFlow. Android's wrapper omits those deliberately — route capture through the FaceCaptureDriver, which is the portable path on both platforms. retryPostResult() is on both: the device-add branch has no capture driver to retry through.
RevocationFlow / KeyRotationFlow
Both expose exactly approve(), cancel(), and state observation. Rotation additionally throws NoKeys at start.
FaceCaptureDriver
submitFaceCapture(captureSession:), retry(), cancel(), currentState(), and state observation.
Configuration
AuthenticatorConfig
| Field | Type | Notes |
|---|---|---|
portalUrl | String | No trailing slash. |
appLabel | String | Shown in audit entries and bundled UI. |
tenantId | String? | nil → default tenant. |
enableLogging | Bool | Defaults to false. Panic reporting is unaffected. |
SignInConfig
What in-app sign-in signs in to.
| Field | Type | Notes |
|---|---|---|
issuer | String | https:// only; http:// for a loopback host in development. The SDK lowercases the scheme and host and drops a trailing /. |
clientId | String | The application with in-app sign-in turned on. |
resource | String? | API audience (RFC 8707). nil → the IdP's default. |
scopes | [String] | Empty → openid. Add offline_access for a refresh token. |
loginHint | String? | The account's email. nil → the key enrolled for clientId, else the most recent key. |
pki | SignInPkiRequest? | A face-PKI operation to run during the sign-in. Defaults to nil. |
Data models
TokenSession
The stored result of an in-app sign-in, returned by currentSession() and on signedIn. Members: accessToken(), expiresAtEpochSecs(), idTokenClaimsJson(), canRefresh(), accessTokenExpired(), needsRefresh(), refresh() (throws RefreshError), authorize(method:url:), observeResponse(url:status:wwwAuthenticate:dpopNonce:), shouldRefreshAfter(status:wwwAuthenticate:). See Using the tokens.
SignInPkiRequest
| Field | Type | Notes |
|---|---|---|
kind | PkiCeremonyKind | publicKeys, sign or decapsulate. |
context | Data / ByteArray | The application's key context, up to 255 bytes. May be empty. |
operand | Data / ByteArray | sign: the payload hash (32 or 64 bytes). decapsulate: the ML-KEM ciphertext. publicKeys: empty. |
scope | PkiKeyScope? | app (default when nil) or tenant. |
PkiResult
Returned on signedIn as pki when the config carried a request: kind, context and scope echoed, plus outcome: PkiOutcome, one of publicKeys(dsaPublicKeySpki:kemPublicKeySpki:), signature(signature:dsaPublicKeySpki:) or sharedSecret(sharedSecret: PkiSharedSecret, kemPublicKeySpki:). Keys are SPKI DER. PkiSharedSecret.takeBytes() returns the 32-byte secret once and wipes the SDK's copy; later calls return nil.
ClientAssertionProvider and ClientAssertionRequest
A confidential client's hook. clientAssertion(request:) returns a fresh RFC 7523 client assertion for one HTTP attempt, or throws ClientAssertionError.Unavailable(details:) (Kotlin ClientAssertionException.Unavailable). The request carries clientId, audience (the issuer, for aud) and dpopJkt (this install's DPoP key thumbprint). Called on an SDK worker thread. See Confidential clients.
Key
| Field | Type |
|---|---|
id | String |
email | String |
clientId | String |
createdAt | String |
pubkeyFingerprint | String |
Branding
| Field | Type | Notes |
|---|---|---|
orgName | String | |
shortMessage | String? | |
logoUrl | String? | |
logoBytes | Data? | Pre-fetched bytes — prefer these over re-fetching logoUrl. |
logoMime | String? | |
primaryColor | String? | |
accentColor | String? |
Branding is cached per relying party on disk. Per-session values — notably a CIBA binding message — are not here; they arrive on the login state instead, so a stale message can't replay on a later sign-in.
RevokedKeyNotice
| Field | Type | Notes |
|---|---|---|
email | String | |
clientId | String | |
appLabel | String | |
terminated | Bool | true for termination, false for ordinary revocation. |
replaced | Bool | true when the key was revoked because the account was enrolled on another device under a tenant that allows one device per user. Never true with terminated. |
OtherDevice
One of the user's other devices that completing an enrollment would sign out, carried by awaitingDeviceReplacementConfirm (registration).
| Field | Type | Notes |
|---|---|---|
deviceName | String? | As that device's own enrollment reported it; nil for a device enrolled before the server recorded it. |
os | String? | "android" / "ios", or nil. |
osVersion | String? | |
lastUsedAt | String | RFC 3339 UTC, the last time that device's key authenticated. |
AuditEntry
| Field | Type |
|---|---|
timestamp | Int64 |
kind | String |
identityId | String? |
note | String |
SignupAttribute
| Field | Type | Notes |
|---|---|---|
key | String | Key your submitted value by this. |
dataType | AttributeDataType | Which control to render. |
label | String | |
required | Bool | |
ordering | Int32 | Render in this order. |
options | [String] | Values for choice. |
constraints | AttributeConstraints? |
AttributeConstraints
| Field | Type |
|---|---|
minLength | Int32? |
maxLength | Int32? |
min | String? |
max | String? |
decimalPlaces | Int32? |
SignupAttributeRejection
| Field | Type | Notes |
|---|---|---|
key | String? | Offending field, or nil for a form-level error. |
message | String | Server's reason. Show inline. |
FaceMetrics
Normalized quality signals from a capture: pitchness, yawness, rollness, centerness, closeness — all Float.
Enums
AttributeDataType
text, integer, decimal, boolean, date, address, choice, coupon, phoneNumber, timezone, locale, unknown
Notes for form rendering: address uses the structured address map on submission rather than the flat values map. coupon cannot be validated on-device — expect a server rejection round-trip. Treat unknown as text so a newer server's attribute doesn't break your form.
CaptureOutcome
succeeded, cancelled, failed(reason: FailureReason)
FaceCaptureRetryReason
faceMismatch (counts against the budget), livenessFailed (does not)
HeadPose
All 15 cases:
normal, normalNotLive, tooFar, tooClose, notCentered, lookingLeft, lookingRight, lookingUp, lookingDown, lookingTopLeft, lookingTopRight, lookingBottomLeft, lookingBottomRight, tiltedLeft, tiltedRight
Used by the lower-level capture surface for framing guidance. The bundled views render this for you.
BarcodeFormat
qrCode, dataMatrix, aztec, pdf417
PushPlatform
ios, android
PkiCeremonyKind
publicKeys, sign, decapsulate
The key operation that a face-PKI ceremony or a SignInPkiRequest asks for.
PkiKeyType
kem, dsa
The key class that keyTypeUnavailable names: kem is the ML-KEM key and dsa is the ML-DSA key.
PkiKeyScope
app, tenant
The keys that a face-PKI operation uses. app, the default, selects the user's keys for the application that asks. tenant selects the user's tenant-wide keys: every application in the tenant that uses the tenant scope gets the same keys for the same user and context. A nil scope on a SignInPkiRequest means app. See Key scope.
SignInState
idle, starting, awaitingFaceCapture(lastError: FaceCaptureRetryReason?), processing, postingResult, postingResultFailed(reason: SignInFailure) (not terminal), exchangingCode, signedIn(expiresAtEpochSecs:session:pki:), failed(reason: SignInFailure)
SignInFailure
signInUnavailable, upgradeRequired, notEnrolled, faceMismatch, livenessFailed, cancelled, network(message:), server(message:), pkiNotAvailable, pkiKeysNotReady, invalidPkiRequest, pkiScopeNotAllowed
Error enums
AuthnInitError, AuthnRuntimeError, SenseCryptInitError, FailureReason, LinkError, PasswordError, SignAssertionError, HybridError, SignInFailure, ClientAssertionError and RefreshError are all documented with causes and recovery in Errors.
Related
- Initialization — opening the SDK.
- Login · Registration · Key management
- UI components — the bundled surfaces.
- Errors — the full error surface.
Error reference
Every error type and failure reason the SenseCrypt Mobile SDK can produce, what causes it, and whether it is recoverable.
Relying party
Integrate your web application as an OIDC relying party against SenseCrypt using any conformant OIDC client library — no SenseCrypt-specific SDK required.