webauthn-client-ktor¶
Codec-neutral Ktor transport for the generic webauthn-client-flow backend contracts.
What it provides¶
KtorPasskeyBackendadapters for registration and authentication.KtorPasskeyContractCodecas the complete wire-contract seam.KtorPasskeyRoutesfor path configuration.- Exact forwarding of decoded registration/authentication state to the matching finish encoder.
The module depends on Ktor client core and webauthn-client-flow. It does not choose an HTTP engine,
content-negotiation plugin, serializer, or Kotlinx implementation.
When to use¶
Use this module when your application wants Ktor transport but owns the payload format, continuation
token, and finish output. Use webauthn-client-ktor-kotlinx instead when your server implements this
repository's default /webauthn/* JSON contract.
How to use¶
Create the HttpClient in the application with the engine and policies appropriate for each target,
then inject it together with a contract codec. The codec's six type parameters keep registration and
authentication input, opaque state, and output independent.
data class RegistrationCommand(val userName: String)
data class RegistrationContinuation(val token: String)
data class RegisteredAccount(val id: String)
data class AuthenticationCommand(val userName: String?)
data class AuthenticationContinuation(val token: String)
data class AuthenticatedAccount(val id: String)
typealias AppContractCodec = KtorPasskeyContractCodec<
RegistrationCommand,
RegistrationContinuation,
RegisteredAccount,
AuthenticationCommand,
AuthenticationContinuation,
AuthenticatedAccount,
>
fun appKtorBackend(
httpClient: HttpClient,
codec: AppContractCodec,
): KtorPasskeyBackend<
RegistrationCommand,
RegistrationContinuation,
RegisteredAccount,
AuthenticationCommand,
AuthenticationContinuation,
AuthenticatedAccount,
> = KtorPasskeyBackend(
httpClient = httpClient,
endpointBase = "https://example.com",
codec = codec,
)
decodeRegistrationStart and decodeAuthenticationStart must return a CeremonyStart containing
both typed options and the backend state. The corresponding finish encoder receives that same state
and the platform's raw response. This is where transaction IDs, signed continuation blobs, or CSRF
bindings belong.
HTTP and failure behavior¶
- All four operations use
POSTwithContent-Type: application/json. - Non-2xx responses throw an exception.
decodeErrormay return a safe diagnostic; otherwise the body is redacted and only its length is reported. - Invalid start payloads become
IllegalArgumentExceptionwith field-level validation details. - Codec, engine, timeout, and backend exceptions propagate through
PasskeyFlow; the application decides how to classify or display them.
How it fits in the system¶
flowchart LR
FLOW["webauthn-client-flow"] --> KTOR["webauthn-client-ktor"]
KTOR --> CODEC["Application contract codec"]
KTOR --> HTTP["Application-owned Ktor HttpClient and engine"]
Pitfalls and limits¶
- Do not use
Unitstate unless the backend genuinely requires no client-carried continuation data. - Do not log or expose raw error bodies; implement
decodeErrorto extract only safe diagnostics. - Retries can replay ceremony operations. Apply retry policy deliberately at the application layer.
- Route configuration changes paths only; it does not change payload semantics.
Status¶
Beta. Mock-engine contract tests cover non-Unit state forwarding for registration and
authentication. Engine/runtime behavior remains the consuming application's responsibility.