iOS Representations#

The Curity HAAPI iOS SDK delivers every HAAPI response as a typed Swift value. HaapiResult is the top-level enum returned by HaapiManager.start, submitForm, and followLink; its .representation case carries a HaapiRepresentation whose concrete type tells you which step the server is asking the client to render.

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

SDK-thrown errors are inside HaapiResult. Network failures, attestation failures, and other framework errors arrive as the third enum case, .error(Error). Match on it the same way you match on .representation and .problem. See Error Handling for the typed HaapiError hierarchy.

Response Hierarchy#

HaapiResult is a Swift enum with three cases. Every call to HaapiManager.start, submitForm, or followLink resolves to one of them:

CaseWhen it surfacesCarries
.representation(HaapiRepresentation)The flow continues with another stepA concrete struct conforming to HaapiRepresentation (or ClientOperationStep)
.problem(ProblemRepresentation)The server rejected the request (RFC 7807)A type conforming to Problem — InvalidInputProblem, AuthorizationProblem, or the base Problem
.error(Error)Framework / transport failureAn Error value — cast to HaapiError for the typed hierarchy

Match on the enum case first, then narrow further by casting the associated value to the concrete step or problem type.

Step Types#

HaapiRepresentation is a Swift protocol implemented by 14 concrete structs. Two distinct protocols capture the model — HaapiRepresentation for renderable steps and ClientOperationStep for steps that delegate to an external operation.

Common fields#

Every step exposes these base fields through the protocol:

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

The 14 step types#

Grouped by purpose:

GroupConcrete typeExtra fields
InteractiveAuthenticatorSelectorSteptitle: Message, authenticators: [AuthenticatorOption]
InteractiveFormStep(form actions inside actions)
UserConsentStep—
Flow controlRedirectionStepredirectAction: Action
PollingStepmainAction, cancelAction?, pollingProperties
ContinueSameStep—
OAuthOAuthAuthorizationResponseStepoauthAuthorizationResponseProperties (carries code)
Client operation (conform to ClientOperationStep)ExternalBrowserClientOperationStep—
BankIdClientOperationStepactivationLink?
EncapClientOperationStep—
WebAuthnRegistrationClientOperationStep—
WebAuthnAuthenticationClientOperationStep—
GenericClientOperationStep—
FallbackGenericRepresentationStepproperties?

Switching on the result#

import IdsvrHaapiSdk

haapiManager.start { result in
    switch result {
    case .representation(let representation):
        handleRepresentation(representation)
    case .problem(let problem):
        handleProblem(problem)
    case .error(let error):
        // Cast to HaapiError for the typed hierarchy — see Error Handling.
        handleError(error)
    }
}

private func handleRepresentation(_ representation: HaapiRepresentation) {
    switch representation {
    case let step as AuthenticatorSelectorStep:
        // step.title.literal, step.authenticators
        // Each AuthenticatorOption carries an Action.Form for selection.
        break
    case let step as InteractiveFormStep:
        // step.actions includes form actions; render their fields as a UIKit form.
        break
    case let step as PollingStep:
        // step.pollingProperties.status, step.mainAction, step.cancelAction
        break
    case let step as OAuthAuthorizationResponseStep:
        // Flow complete — extract the authorization code.
        let code = step.oauthAuthorizationResponseProperties.code
        break
    case let step as ClientOperationStep:
        // Delegate to the platform (BankID, WebAuthn, external browser, …)
        break
    default:
        // GenericRepresentationStep, ContinueSameStep, UserConsentStep, RedirectionStep.
        break
    }
}

Actions#

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

CaseactionTypeCarriesWhen to use
Action.form(FormAction).formFormActionModelThe most common action — render fields, submit values
Action.selector(SelectorAction).selector[Action] (nested options)Server provides a choice (e.g., device selector); each option is itself an Action
Action.clientOperation(ClientOperationAction).clientOperationA 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

FormAction#

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

let formAction: FormActionModel = …

let parameters: [String: Any] = [
    formAction.fields[0].name: "user@example.com",
    formAction.fields[1].name: "secret"
]

haapiManager.submitForm(formAction, parameters: parameters) { result in
    handleResult(result)
}

submitForm’s parameters accept any JSON-serialisable value for non-GET methods; GET form actions require [String: String]. See HAAPI Flow for the full parameter-type semantics across platforms.

The FormActionModel carries:

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

ClientOperationAction#

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

Form Fields#

FormField is a Swift enum with 7 cases:

Common fields#

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

Rendering guide#

FormField caseUIKit elementNotes
.hiddennoneInclude value in submit params automatically — don’t render
.textUITextFieldInspect kind for keyboard type (.email, .tel, etc.)
.usernameUITextFieldautocapitalizationType = .none
.passwordUITextFieldisSecureTextEntry = true
.selectUIPickerView or UIButton setRender options as choices
.checkboxUISwitchRespect readOnly flag
.contextnoneHidden context data (e.g., WebAuthn challenge) — don’t render

Problems#

Problem responses follow RFC 7807. iOS uses a Problem protocol with three concrete types:

TypeproblemTypeExtra fields
Problem (base)base value(base only)
InvalidInputProblem.invalidInputinvalidFields: [InvalidField] (each: name, reason?, detail: Message), errorDescription?
AuthorizationProblem.authorizationerror, 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 enum. Match its cases:

CaseFields
.successfulToken(SuccessfulTokenResponse)accessToken, tokenType?, scope?, expiresIn, refreshToken?, idToken?
.errorToken(ErrorTokenResponse)error, errorDescription?, errorUri?
.error(Error)Framework / transport error

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
typeString?Hint for the media type of the linked resource

Render link sets alongside the main form — typically as secondary buttons or text links.

Classify before acting#

Not every link is a HAAPI step. Read link.kind and act on the result rather than following every link:

LinkKindMeaningWhat to do
.haapiA HAAPI resourceawait haapiManager.followLink(link)
.inlineImageAn image, such as a BankID QR codeRender it in place; never follow it
.externalContent for the platformHand href to the system browser or another app
switch link.kind {
case .haapi:
    let result = await haapiManager.followLink(link)
    // handle result as any other step
case .inlineImage:
    render(link.href)          // e.g. a data: QR image
case .external:
    guard let url = URL(string: link.href) else { return }
    UIApplication.shared.open(url)
}

kind is derived from rel and type only — it is pure, performs no network access, and never inspects the link’s origin. The rules are evaluated in order:

  1. a type of image/* is .inlineImage;
  2. a rel of download or authorization-response is .external;
  3. a scheme other than http/https is .external;
  4. any other declared type is .external;
  5. otherwise — including when type is absent — it is .haapi.

A link with no type is a HAAPI resource, per the HAAPI data model, and must be fetched with an authenticated request. Do not treat a missing type as a reason to compare the link’s origin against your base URL.

followLink additionally refuses a link whose target is not the configured identity server, comparing scheme and host. It returns HaapiErrorCode.nonHaapiLink and sends nothing — see Error Handling.

If you implement the UI layer yourself, the UIKit framework exposes the same classification on LinkItemModel.kind — see UI Extensibility.

Related: HAAPI Flow · OAuthTokenManager · Error Handling · iOS SDK · iOS Reference (DocC for the full type signatures)

Was this helpful?