HaapiTokenManager#

HaapiTokenManager is the core primitive of the Driver Layer. It mints DPoP-bound HAAPI access tokens, generates proof tokens for outgoing requests, and tracks the cryptographic material that ties the flow together. Use it directly when neither the iOS HaapiClient nor the Android OkHttp interceptor fits your transport — for example, when you ship requests through a custom HTTP stack that you cannot reroute through either convenience.

Construction#

Build the manager with the token endpoint URL and a client ID. Per-platform configuration knobs (token binding, risk assessment, client authentication) chain onto the builder; each has its own topic page in this section.

let tokenEndpoint = URL(string: "https://idsvr.example.com/oauth/v2/oauth-token")!
let clientId = "haapi-ios-client"

let haapiTokenManager = HaapiTokenManagerBuilder(
    tokenEndpoint: tokenEndpoint,
    clientId: clientId
).build()

Optional builder methods — .setTokenBoundConfiguration(...), .setRiskAssessmentConfiguration(...), .setClientAuthenticationMethod(...) — are documented on the individual topic pages.

Direct Token Retrieval#

Ask the manager for an access token and a paired DPoP proof, then add both to the outgoing HTTP request yourself:

let httpRequestMethod = "GET"
let httpRequestTargetURL = URL(string: "https://idsvr.example.com/dev/oauth/authorize")!

var dpopAccessTokenInfo: Result<DpopAccessTokenInfo, HaapiError>?
haapiTokenManager.getHaapiToken { result in
    dpopAccessTokenInfo = result
}

// From the resolved info, build the headers:
let authorizationHeaderValue = dpopAccessTokenInfo?.authorizationHeaderValue()
let dpopHeaderValue = dpopAccessTokenInfo?.dpopHeaderValue(
    httpRequestMethod,
    httpRequestTargetURL
)

// Attach authorizationHeaderValue to the Authorization header
// and dpopHeaderValue to the DPoP header on your URLRequest.

When the request succeeds, the response may contain a DPoP-Nonce header. The manager tracks this automatically and applies it on the next call. The deprecated dpopNonce parameter is still honored for backward compatibility, but new code should not pass it. See Upgrade — DPoP Nonce Auto-Management .

Session-Identifier Handling#

The HAAPI flow uses a Session-Id header to thread state across requests. When you bypass HaapiClient (iOS) or the OkHttp interceptor (Android), you handle the session identifier yourself:

  1. Read the Set-Session-Id header from each response.
  2. Send the value back on the next request via the Session-Id header.
  3. If the server emits a new Set-Session-Id mid-flow, switch to the new value immediately.
// 1. Read Set-Session-Id from each response.
let sessionId = httpResponse.value(forHTTPHeaderField: "Set-Session-Id")

// 2. Send it back on the next request.
var nextRequest = URLRequest(url: nextUrl)
if let sessionId {
    nextRequest.setValue(sessionId, forHTTPHeaderField: "Session-Id")
}

// 3. If a later response emits a new Set-Session-Id, overwrite and continue.

Session identifiers are bound to the access token’s DPoP key. When the key changes — for example, after the manager is reconstructed — the previous session identifier is invalid and a new flow must start.

Lifecycle#

Only one active HaapiTokenManager may exist for a given name (the iOS name property or the Android instance identifier). On iOS, name defaults to clientId and can be overridden in the builder. Creating a second active instance with the same name raises an “already exists” error.

// Release the lock and tear down resources.
haapiTokenManager.close()

Calling any token-fetching method on a closed manager raises an “already closed” error.

When to Prefer the Helpers#

HaapiClient on iOS and addHaapiInterceptor(haapiTokenManager) on Android take care of all of the above — DPoP proof per request, automatic nonce tracking, session-identifier threading. Reach for direct HaapiTokenManager use only when your requests cannot route through them.

Was this helpful?