Android Representations#

The Curity HAAPI Android SDK delivers every HAAPI response as a typed Kotlin value. HaapiResponse is the sealed root returned by HaapiManager.start, submitForm, and followLink; concrete subtypes — HaapiRepresentation for step-shaped responses and ProblemRepresentation for RFC 7807 errors — tell you what the server is asking the client to do.

The same model hierarchy exists on iOS and React Native — see iOS Representations and React Native Representations for the per-platform shape. This page is the Android narrative reference.

SDK-thrown errors are separate. Network failures, attestation failures, and other framework errors arrive through the coroutine’s Throwable channel (or as failed Result values), not as a HaapiResponse variant. Catch them with try/catch and cast to HaapiError for the typed hierarchy. See Error Handling .

Response Hierarchy#

HaapiResponse is a sealed Kotlin interface with two sealed children:

SiblingWhen it surfacesImplemented by
HaapiRepresentationThe flow continues with another step14 concrete step classes (8 HaapiRepresentations + 6 ClientOperationStep siblings)
ProblemRepresentationThe server rejected the request (RFC 7807)Problem, InvalidInputProblem, AuthorizationProblem

Branch with a when expression on the response, then narrow on the concrete step or problem class.

Step Types#

HaapiRepresentation is the sealed interface for renderable steps. A parallel ClientOperationStep sealed interface captures steps that delegate to an external operation (BankID, WebAuthn, external browser, …).

Common fields#

Every step exposes these base fields:

FieldTypeDescription
typeRepresentationTypeHAAPI representation type (8 values)
metadataMetadata?Template area and view name
actionsList<Action>Available actions for this step
linksList<Link>Navigation links (e.g., “forgot password”)
messagesList<UserMessage>User-facing messages to display
propertiesProperties?Step-specific properties

The 14 step types#

Grouped by purpose:

GroupConcrete classExtra fields
InteractiveAuthenticatorSelectorSteptitle: Message, authenticators: List<AuthenticatorOption>
InteractiveFormStep(form actions inside actions)
UserConsentStep
Flow controlRedirectionStepredirectAction: Action
PollingStepmainAction, cancelAction?, properties: PollingProperties
ContinueSameStep
OAuthOAuthAuthorizationResponseStepproperties: OAuthAuthorizationResponseProperties (carries code)
Client operation (implement ClientOperationStep)ExternalBrowserClientOperationStep
BankIdClientOperationStepactivationLink?
EncapClientOperationStep
WebAuthnRegistrationClientOperationStep
WebAuthnAuthenticationClientOperationStep
GenericClientOperationStep
FallbackGenericRepresentationStepproperties?

Branching on the result#

import se.curity.identityserver.haapi.android.sdk.models.*
import se.curity.identityserver.haapi.android.sdk.models.actions.*

val response: HaapiResponse = haapiManager.start()

when (response) {
    is HaapiRepresentation -> handleRepresentation(response)
    is ProblemRepresentation -> handleProblem(response)
}

private fun handleRepresentation(representation: HaapiRepresentation) {
    when (representation) {
        is AuthenticatorSelectorStep -> {
            // representation.title.literal, representation.authenticators
            // Each AuthenticatorOption carries an Action.Form for selection.
        }
        is InteractiveFormStep -> {
            // representation.actions contains form actions;
            // render their fields as a Compose / View form.
        }
        is PollingStep -> {
            // representation.properties.status, representation.mainAction, representation.cancelAction
        }
        is OAuthAuthorizationResponseStep -> {
            // Flow complete — extract the authorization code.
            val code = representation.properties.code
        }
        is ClientOperationStep -> {
            // Delegate to the platform (BankID, WebAuthn, external browser, …)
        }
        else -> {
            // GenericRepresentationStep, ContinueSameStep, UserConsentStep, RedirectionStep.
        }
    }
}

Actions#

Actions represent operations the user can perform. They live under the sealed Action class:

SubclassCarriesWhen to use
Action.Formmodel: FormActionModelThe most common action — render fields, submit values
Action.Selectormodel: SelectorActionModel (nested options as List<Action>)Server provides a choice (e.g., device selector); each option is itself an Action
Action.ClientOperationmodel: ClientOperationActionModelExternal handling required (BankID, WebAuthn, browser launch)

Every action also carries:

FieldTypeDescription
kindActionKindSemantic meaning: Login, Cancel, Redirect, Poll, etc. (17 values)
titleMessage?Display title for buttons / labels

Action.Form#

Submitting a form is the SDK’s primary write operation:

val formAction: Action.Form =

val parameters: Map<String, Any> = mapOf(
    formAction.model.fields[0].name to "user@example.com",
    formAction.model.fields[1].name to "secret"
)

val next = haapiManager.submitForm(formAction, parameters)

submitForm’s parameters accept any JSON-serialisable value (String, Number, Boolean, nested maps, lists) for non-GET methods; GET form actions require Map<String, String>. See HAAPI Flow for the full parameter-type semantics across platforms.

The FormActionModel carries:

FieldTypeDescription
fieldsList<FormField>Form fields to render
methodStringHTTP method (e.g., "POST")
hrefStringTarget URI
actionTitleMessage?Submit button text

Action.ClientOperation#

Six sub-types of ClientOperationActionModel, each with its own fields: ExternalBrowser, BankId, Encap, WebAuthnRegistration, WebAuthnAuthentication, Generic. Each model includes continueActions and errorActions lists for post-operation flow.

Form Fields#

FormField is a sealed Kotlin class with 7 subclasses:

Common fields#

FieldTypeDescription
nameStringParameter key for submission
valueString?Current / default value
labelMessage?Display label
placeholderMessage?Placeholder text
isRequiredBooleanWhether the field is required

Rendering guide#

FormField subclassCompose / View elementNotes
FormField.HiddennoneInclude value in submit params automatically — don’t render
FormField.TextTextField / EditTextInspect kind for keyboard type (Email, Tel, Number, Url, Color)
FormField.UsernameTextField / EditTextDisable autocapitalisation
FormField.PasswordTextField / EditTextvisualTransformation = PasswordVisualTransformation()
FormField.SelectDropdownMenu / SpinnerRender options as choices
FormField.CheckboxSwitch / CheckboxRespect readonly flag
FormField.ContextnoneHidden context data (e.g., WebAuthn challenge) — don’t render

Problems#

Problem responses follow RFC 7807. Android exposes them as concrete ProblemRepresentation subclasses:

Classtype (ProblemType)Extra fields
Problembase value(base only)
InvalidInputProblemInvalidInputProbleminvalidFields: List<InvalidField> (each: name, reason?, detail: Message), errorDescription?
AuthorizationProblemErrorAuthorizationResponseProblemerror, errorDescription?, iss?

InvalidInputProblem.invalidFields is the right hook for showing field-level validation errors inline in your form.

Token Responses#

OAuthTokenManager.fetchAccessToken, refreshAccessToken, and revokeRefreshToken return a TokenResponse sealed interface. Branch its variants:

VariantFields
SuccessfulTokenResponseaccessToken, tokenType?, scope?, expiresIn, refreshToken?, idToken?
ErrorTokenResponseerror, errorDescription?, errorUri?

SDK-thrown errors (network, attestation, framework) come back through the coroutine’s exception channel, not as a TokenResponse variant. See OAuthTokenManager for the full lifecycle, and Error Handling for the difference between RFC-6749 OAuth errors (values) and framework errors.

Each Link carries:

FieldTypeDescription
hrefStringTarget URI
relStringRelationship type (e.g., forgot-password)
titleMessage?Display text

Render link sets alongside the main form — typically as secondary buttons or text links. Submit a link via haapiManager.followLink(link) to navigate.

Was this helpful?