SenseCrypt Docs
SDKs & appsMobile SDK

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.

MemberSwiftKotlinNotes
Usable keyskeys: [Key]keys: List<Key>Filtered to keys with live hardware material.
Current keycurrentKey: Key?currentKey: Key?
Branding lookupbrandingFor(keyId:) -> Branding?brandingFor(keyId): Branding?nil → fall back to a default icon.
Audit logauditLog(limit:) -> [AuditEntry]auditLog(limit): List<AuditEntry>limit defaults to 50.
Start registrationstartRegistrationFlow(email:clientId:sessionId:) throwsstartRegistrationFlow(email, clientId, sessionId, systemPasskeyMode = false)Throws AuthnInitError.
Start loginstartLoginFlow() -> LoginFlowstartLoginFlow(): LoginFlowDoes not throw.
Start in-app sign-instartSignInFlow(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 sessioncurrentSession() -> TokenSession?, signOut()currentSession(): TokenSession?, signOut(), dpopInterceptor(): okhttp3.InterceptorThe 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 providersetClientAssertionProvider(_:), 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 ceremonystartPkiCeremonyFlow() -> PkiCeremonyFlowstartPkiCeremonyFlow(): PkiCeremonyFlowDoes not throw. Face-PKI tenants only.
Start face reportstartFaceReportFlow(rpId:clientDataHashB64url:credentialIdB64url:) -> FaceReportFlowstartFaceReportFlow(rpId, clientDataHashB64url, credentialIdB64url): FaceReportFlowDoes 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(): FaceReportFlowAndroid 9–13 system-passkey path: adopts the newest parked assertion.
Sign an assertionsignAssertion(rpId:clientDataHashB64url:credentialIdB64url:) throws -> WebAuthnAssertionsignAssertion(rpId, clientDataHashB64url, credentialIdB64url): WebAuthnAssertionSynchronous and offline. Swift also takes raw Data.
Passkey identitiespasskeyIdentities() -> [PasskeyIdentity], publishPasskeyIdentities() async -> Int, clearPublishedPasskeyIdentities() asyncpasskeyIdentities(): 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): HybridCeremonyFlowAndroid only. parseHybridQr and startHybridCeremonyFlow throw HybridException.
Tenant appstenantApps(keyId:) -> [TenantApp]tenantApps(keyId): List<TenantApp>The apps of the key's tenant, from the local branding cache.
Branding syncsyncBranding(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 revocationstartRevocationFlow(keyId:) throwsstartRevocationFlow(keyId)
Start rotationstartKeyRotationFlow() throwsstartKeyRotationFlow()Throws NoKeys when empty.
Rotation hinttakeKeyRotationHint() -> BooltakeKeyRotationHint(): BooleanOne-shot; reading clears it.
Stage push tokenupdatePushToken(token:platform:)updatePushToken(token, platform)Fire-and-forget.
Upload push tokensyncPushToken()syncPushToken()Fire-and-forget.
Load modelsinitializeInferenceEngine() async throwsinitializeInferenceEngine(context) — suspendIdempotent.

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.

FlowSwift observationKotlin observation
LoginFlowstateStream(): AsyncStream<LoginState>state: SharedFlow<LoginState>
SignInFlowstateStream(): AsyncStream<SignInState>state: SharedFlow<SignInState>
RegistrationFlowstateStream(): AsyncStream<RegistrationState>state: SharedFlow<RegistrationState>
PkiCeremonyFlowstateStream(): AsyncStream<PkiCeremonyState>state: SharedFlow<PkiCeremonyState>
FaceReportFlowstateStream(): AsyncStream<FaceReportState>state: SharedFlow<FaceReportState>
HybridCeremonyFlow—subscribe(listener) and currentState() on the flow object
FaceCaptureDrivercaptureStateStream(): AsyncStream<FaceCaptureUiState>state: SharedFlow<FaceCaptureUiState>
RevocationFlowstateStream(): AsyncStream<RevocationState>state: StateFlow<RevocationState>
KeyRotationFlowstateStream(): 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

MemberPurpose
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.

MemberPurpose
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() / currentStateSynchronous state read.

PkiCeremonyFlow

Answers a face-PKI ceremony. Result is delivered to the application, never to your app. See Face PKI.

MemberPurpose
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.
currentStateSynchronous 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.

MemberPurpose
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.
currentStateSynchronous state read.

HybridCeremonyFlow (Android)

Runs the cross-device passkey ceremony for a scanned FIDO:/ code. See Passkeys and the face report.

MemberPurpose
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

MemberPurpose
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

FieldTypeNotes
portalUrlStringNo trailing slash.
appLabelStringShown in audit entries and bundled UI.
tenantIdString?nil → default tenant.
enableLoggingBoolDefaults to false. Panic reporting is unaffected.

SignInConfig

What in-app sign-in signs in to.

FieldTypeNotes
issuerStringhttps:// only; http:// for a loopback host in development. The SDK lowercases the scheme and host and drops a trailing /.
clientIdStringThe application with in-app sign-in turned on.
resourceString?API audience (RFC 8707). nil → the IdP's default.
scopes[String]Empty → openid. Add offline_access for a refresh token.
loginHintString?The account's email. nil → the key enrolled for clientId, else the most recent key.
pkiSignInPkiRequest?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

FieldTypeNotes
kindPkiCeremonyKindpublicKeys, sign or decapsulate.
contextData / ByteArrayThe application's key context, up to 255 bytes. May be empty.
operandData / ByteArraysign: the payload hash (32 or 64 bytes). decapsulate: the ML-KEM ciphertext. publicKeys: empty.
scopePkiKeyScope?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

FieldType
idString
emailString
clientIdString
createdAtString
pubkeyFingerprintString

Branding

FieldTypeNotes
orgNameString
shortMessageString?
logoUrlString?
logoBytesData?Pre-fetched bytes — prefer these over re-fetching logoUrl.
logoMimeString?
primaryColorString?
accentColorString?

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

FieldTypeNotes
emailString
clientIdString
appLabelString
terminatedBooltrue for termination, false for ordinary revocation.
replacedBooltrue 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).

FieldTypeNotes
deviceNameString?As that device's own enrollment reported it; nil for a device enrolled before the server recorded it.
osString?"android" / "ios", or nil.
osVersionString?
lastUsedAtStringRFC 3339 UTC, the last time that device's key authenticated.

AuditEntry

FieldType
timestampInt64
kindString
identityIdString?
noteString

SignupAttribute

FieldTypeNotes
keyStringKey your submitted value by this.
dataTypeAttributeDataTypeWhich control to render.
labelString
requiredBool
orderingInt32Render in this order.
options[String]Values for choice.
constraintsAttributeConstraints?

AttributeConstraints

FieldType
minLengthInt32?
maxLengthInt32?
minString?
maxString?
decimalPlacesInt32?

SignupAttributeRejection

FieldTypeNotes
keyString?Offending field, or nil for a form-level error.
messageStringServer'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.

On this page