This document describes the Hypermedia Authentication API (HAAPI) that allows OAuth clients to request tokens from the Curity Identity Server in an API-driven way, i.e., without requiring a browser to perform the user authentication and consent interactions.
Curity Identity Server supports a wide range of authentication methods, with highly dynamic flows that depend on previous user actions as well on contextual information.
Due to this characteristic, HAAPI adopts a hypermedia-driven style, where the client application is guided through the flow based on hypermedia controls such as forms and links, present in the HAAPI responses.
The client application should use these responses and controls to drive the UI presented to the user and obtain the information required to produce the next request.
For this matter, HAAPI uses a JSON-based custom media type with the application/vnd.auth+json media type identifier.
The client application must always send an Accept header including this media type identifier, to inform Curity Identity Server that the request is an HAAPI request.
This is required because HAAPI shares most of the URIs that already exist for the traditional HTML-based interactions.
For a broader overview of the API, checkout the recorded Webinar and the getting started articles in the resource library available on our Web site.
All requests to HAAPI require a HAAPI access token.
In order to obtain it, a client application must perform an OAuth 2.0 token request to the token endpoint, using the client credentials grant.
The HAAPI access token is a DPoP-bound token and not a bearer token.
Due to this, the token request also needs a DPoP header with a proof token (see OAuth 2.0 Demonstration of Proof-of-Possession draft specification which may change as it is finalized.)
For an introduction to DPoP, checkout the Demonstration of Proof-of-Possession overview in the resource library available on our Web site.
The following example request illustrates the HAAPI access token request, using a client secret as the client authentication method:
POST /dev/oauth/token HTTP/1.1
In order for the token to be issued, the client must also have the haapi capability enabled in the server configuration.
The HAAPI access token must be used on all HAAPI requests, by adding it to the Authorization header and using the DPoP scheme, along side with a per-request DPoP proof token present in the DPoP header, as illustrated in the following request:
Authorization: DPoP ey...Yw
Tokens requests can also use an attestation-based authentication method, in alternative to client secrets.
This method is adequate for use by public clients, such as native clients or browser-based clients, which cannot hold static client secrets.
The attestation process uses client-side platform specific functionalities to verify the client application identity.
Due to that, the recommended way is for client applications to use a Curity provided client SDK (Software Development Kit) to perform attestation and manage API access tokens.
Attestation settings are defined in the client configuration section and vary with the client’s platform, as described in the following sections.
Some more advanced configurations can be made via client attestation policies, namely defining the TTL of HAAPI access tokens (haapi-access-token-ttl setting).
A statically configured OAuth client can use Android based attestation via the attestation client configuration.
The following configuration excerpt shows how to use this configuration element.
The package-name property must have the client application Android package name.
The signature-digest property must have the SHA-256 hash of the signing certificate, encoded using Base64.
To obtain this value, run the signingReport gradle task on the Android Studio project, look for the SHA-256 line and convert its value to Base64.
$ ./gradlew signingReport
Valid until: Wednesday, July 5, 2045
$ echo "67:60:CA:11:93:B6:5D:61:56:42:70:29:A1:10:B3:86:A8:48:C7:33:83:7B:B0:54:B0:0A:E3:E1:4A:7D:A0:A4" | xxd -r -p | base64
To support client applications running in Android emulators, namely during the development phase, a custom Android attestation policy needs to be defined in facilities
Then, the client attestation configuration needs to explicitly refer this policy
Notice that custom policies should only be used for development purposes or to support special devices, since they may reduce the Android attestation security.
On the client side, the attestation protocol is performed automatically by the Curity provided SDK, including the use of native Android attestation APIs.
A statically configured iOS client can use iOS attestation (i.e. Apple Device Check services)
by configuring the iOS attestation settings of the client. These settings include the app-id of the iOS client app,
that is made up of the Apple-assigned teamId together with the app’s bundleId, separated by a .. For example,
when the teamId is 01234abcde and the app’s bundleId is app.curity.io, then the AppId to configure is
01234abcde.app.curity.io. This value is needed to identify the attested client app.
Further configuration of iOS related attestation is done by a shared iOS Attestation Policy in Curity’s facilities. Here
you can set properties to:
When a client does not configure a particular iOS Attestation Policy, a default policy is applied that is comparable
to a policy with a production-mode and uses Apple’s CA to verify attested credential data.
Note that when custom trust-anchors are used in an iOS Attestation Policy, they must be provided in PEM-format.
When a iOS client is successfully attested, a CAT is issued that the client can exchange for a HAAPI token, similarly to
how web- and Android clients do.
A browser-based OAuth client needs to be properly configured in Curity before it can perform a successful attestation and use HAAPI.
Currently, this is only possible for statically configured clients and involves two parts.
First, the HTTP origin where the browser-based application is running needs to be added to the allowed-origins list and attestation needs to be set to web.
The haapi capability also needs to be enabled, similarly to what happens for the other client types.
The following snippet exemplifies these configuration requirements, for a browser-based client application running from https://example.com:1234.
Finally, the client may optionally use a custom attestation policy.
For that, a new web-policy needs to be defined under facilities/client-attestation.
This policy can then override the default attestation behavior characteristics:
After creating the custom policy, the static client configuration needs to refer it, as shown in the next snippet.
Note that using a custom policy that changes the default behavior may compromise the security characteristics of the system.
It is possible to completely disable the attestation validation performed for a specific configured client.
This is achieved by setting attestation/disable-attestation-validation under the client’s configuration.
The client application should still perform the attestation protocol, using the provided SDKs, however the attestation data will not be validated.
Disabling attestation validation for a client allows any application to act as that client.
Therefore, this should only be used in non-production environments, as a way to enable some testing scenarios (e.g. testing iOS applications running on simulators and not real devices).
It may be difficult to understand when problems happen because, by the nature of client attestation on a browser,
a lot of things happen in the background (generation of cryptographic keys, execution of binary code, exchange of
Problems might occur, for example, due to users having older browsers which do not have the most recent Web Crypto API or
cannot execute WebAssembly. We have also seen browsers that appear to “freeze” a session while the user likely closes
the window, only to restart again much later and attempt to continue an authentication flow when the temporary tokens stored
by the browser have long expired.
in the Curity Identity Server.
window['se:curity:web-cat:debug'] = true
Refer to the
haapi-web-driver package documentation
for more details.
On the server side, the logger called se.curity.identityserver.controllers.cat.RequestModel, in particular, will log information about
requests from Web CAT Clients (look for the CAT request ... message).
CAT request ...
On successful CAT issuance, se.curity.identityserver.controllers.cat.CatController will log the full attestation
data collected on the client (look for the messages containing WebAttestationData and Successfully issued a CAT...).
Successfully issued a CAT...
Make sure to enable DEBUG-level logging for these loggers in non-production environments.
HAAPI was designed to be used in cross origin browser-based applications, i.e., applications that have a different origin than the one where HAAPI is located.
Due to that, HAAPI uses a custom header and not cookies to communicate the state required through the several steps that constitute an authorization and authentication flow.
This state management protocol is based on two headers:
Session identifiers are bound to access token DPoP keys, meaning if those keys change (e.g. due to a new access token being requested), then a new flow needs to be started.
It is possible to use HAAPI to create an API-driven front-channel user interface, such as a Single Page Application (SPA), as an alternative to the template driven approach documented on chapter Front-End Development.
See section API Driven UI for more information.
Curity provides a number of SDKs that allow the development of tools to extend and integrate with the Curity Identity Server.
The following HAAPI SDKs are currently available to help develop client applications that use HAAPI.