Hypermedia Authentication API

Introduction

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.curity.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 the HAAPI shares most of the URIs that already exist for the traditional HTML-based interactions.

HAAPI is currently under development and disabled by default. To enable it, define the se.curity.haapi.enable system property with the value true when starting Curity Identity Server.

Access control

All requests to HAAPI require an API Access Token (AAT). In order to obtain an AAT, a client application must perform an OAuth 2.0 token request to the token endpoint, using the client credentials grant.

The AAT 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.)

The following example request illustrates the AAT token request, using a client secret as the client authentication method:

POST /dev/oauth/token HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJqd2siOnsiYWxnIjoiUFMyNTYiLCJlIjoiQVFBQiIsImV4dCI6dHJ1ZSwia2V5X29wcyI6WyJ2ZXJpZnkiXSwia3R5IjoiUlNBIiwibiI6InhYRTB3Um55MVUtbmNSZnd4RUt4WlhJMzJmOTR5NDRlSGpTUnBwSjFmdDFwUEtwanZydlIwWXc5dGo2Zm9GMVJJeDJKdVJmamFLQURNSlpPTUd3Mks2eERpUkFXMzh5Y19faldLMUMxMFY2X3NxZkNSeU5BRFVtNUlrTzcxOXNYRW5iZTU1dVd6aTlCX3VyZ0tZQ1VpcTI1MXdRRC1UbXdRbUpfWEpabmhDdVlmbm4tRzcxWmJhNFMxdGJPS1F5dzlmOHVtRFFOQXVwTlptUU1oVW9xbTcxbm1qWkVGSWtvWlNtaWRtdHctd0pEZVN4Z3AtU2pVTXFPYk1XT2IwOWNLUF9kUmZyTlhaYi12UjloNVBUUm92aC1nX1lOODl4SU5rUld6cld0akxLdGtVLS02R2xkXzhoUW1uajlMVDlRMFFJdmFtVWI0VFlGVFNXcWNvZkFBUSJ9LCJhbGciOiJQUzI1NiIsInR5cCI6ImRwb3Arand0In0.eyJqdGkiOiJjZjdkNmZmYy1iYWY5LTQ5NTgtOWViYy1jYmY1NTQ4OGNlZTciLCJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9sb2NhbGhvc3Q6ODQ0My9kZXYvb2F1dGgvdG9rZW4iLCJpYXQiOjE1OTI1ODE0NDN9.vquk9ES8KDU-kY2dd_t5XQM3NfhOiXVbB_qr8iNzdFhHf7C0EMa4-TVs6LlYvVmfujWeoyLkcjqNi2qXg3CY9uZSqdS3qcdjKjt6antieZLVrGNNYkBFtikCzz2nNWjh9JoAtTgo7E3Hs20FhFtAMLWMc8XL2T1ADDkHwhgDKLTKPA8wbLwInegaICqtcEojFv9LIAapSAwpGyU4-CcoHlihJc6u1tb6rta7jXeLvxq_e8yo3ZH9AYYOT0dh_cf6WEEhTv4IqcA5kyIUWuoQGwJsicl9t2v5vQclVglyQRvEQQIO6YR5yXJbKczqqb5CtZvXRHEGAyO0iMxfuLC6vQ
Origin: https://example.com

client_id=client-one&client_secret=client-secret&scope=urn:se:curity:scopes:api&grant_type=client_credentials

Notice:

  • The request DPoP header, containing the DPoP proof token.
  • The request payload with grant_type set to client_credentials and using the client_secret field.
  • The scope set to urn:se:curity:scopes:api, signalling that the requested token is a AAT.

In order for the token to be issued, the client must also have the authorization-api-client capability enabled in the server configuration.

Warning

Release 5.3 doesn’t allow setting or viewing this capability on the Web UI configuration interface. In alternative, use RESTCONF or the Identity Server CLI:

set profiles profile <the-profile-name> oauth-service settings authorization-server client-store config-backed client client-one capabilities authorization-api-client

The AAT 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:

GET /dev/oauth/authorize?client_id=client-one&response_type=code&...
Host: example.com
Accept: application/vnd.curity.auth+json
Authorization: DPoP ey...Yw
DPoP: eyJqd2siOnsiYWxnIjoiUFMyNTYiLCJlIjoiQVFBQiIsImV4dCI6dHJ1ZSwia2V5X29wcyI6WyJ2ZXJpZnkiXSwia3R5IjoiUlNBIiwibiI6InhYRTB3Um55MVUtbmNSZnd4RUt4WlhJMzJmOTR5NDRlSGpTUnBwSjFmdDFwUEtwanZydlIwWXc5dGo2Zm9GMVJJeDJKdVJmamFLQURNSlpPTUd3Mks2eERpUkFXMzh5Y19faldLMUMxMFY2X3NxZkNSeU5BRFVtNUlrTzcxOXNYRW5iZTU1dVd6aTlCX3VyZ0tZQ1VpcTI1MXdRRC1UbXdRbUpfWEpabmhDdVlmbm4tRzcxWmJhNFMxdGJPS1F5dzlmOHVtRFFOQXVwTlptUU1oVW9xbTcxbm1qWkVGSWtvWlNtaWRtdHctd0pEZVN4Z3AtU2pVTXFPYk1XT2IwOWNLUF9kUmZyTlhaYi12UjloNVBUUm92aC1nX1lOODl4SU5rUld6cld0akxLdGtVLS02R2xkXzhoUW1uajlMVDlRMFFJdmFtVWI0VFlGVFNXcWNvZkFBUSJ9LCJhbGciOiJQUzI1NiIsInR5cCI6ImRwb3Arand0In0.eyJqdGkiOiIxZWE1ODY2OS01OTIwLTRhMmMtOGU0MS05NTMyMDAyZGQxODAiLCJodG0iOiJHRVQiLCJodHUiOiJodHRwczovL2xvY2FsaG9zdDo4NDQzL2Rldi9vYXV0aC9hdXRob3JpemUiLCJpYXQiOjE1OTI1ODE0NDN9.G0MTv82emHMNE2VLwLj57uBcKMLdIh1IFzQaB_qRgWwzOQL6nmfvUNQQzHKkPUjkP4B8M3FK7PH9w7hyJOBCiQqNnFGBCUbsV67zCGpGG7gO1u74o6-_yfiydQOFrZJZaib0vD-P9471KhLq0NikUT9-rUghDxt1o2OLDDbRKM3am_iLCeiNoeB9uMR6iimyXKwphS1RaYDHO7k_82-8G1soGm-EF40St7_kMZbSUR4T_XKjp0hZKx-U5FuKnGzd_4SUpT7kTrFqMv6COjg9GbGqyNS4glfYawPywHyZcAHwPSeycu6G48PHaX_N1v-mVgDFo80ITSCBgQycm-sfBA

Client attestation

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.

Android client attestation configuration

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.

<authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
    <client-store>
        <config-backed>
            <client>
                <id>the-client-id</id>
                <attestation>
                  <android>
                      <package-name>com.example.client.app</package-name>
                      <signature-digest>Z2DK...9oKQ=</signature-digest>
                  </android>
                </attestation>
            </client>
        </config-backed>
    </client-store>
</authorization-server>

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.

Listing 335 Obtain the signing certificate hash and convert it to Base64.
$ ./gradlew signingReport
...
SHA-256: 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
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
Z2DKEZO2XWFWQnApoRCzhqhIxzODe7BUsArj4Up9oKQ=

To support client applications running in Android emulators, namely during the development phase, a custom Android attestation policy needs to be defined in facilities

<config xmlns="http://tail-f.com/ns/config/1.0">
  <facilities xmlns="https://curity.se/ns/conf/base">
      <client-attestation>
          <android-policy xmlns="https://curity.se/ns/conf/client-attestation">
              <id>the-emulator-policy-name</id>
              <verify-boot-state>false</verify-boot-state>
              <minimum-security-level>software</minimum-security-level>
              <override-certificate-chain-validation>
                  <do-not-validate-certificate-chain/>
              </override-certificate-chain-validation>
          </android-policy>
      </client-attestation>
  </facilities>
</config>

Then, the client attestation configuration needs to explicitly refer this policy

<authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
    <client-store>
        <config-backed>
            <client>
                <id>the-client-id</id>
                <attestation>
                  <android>
                      <package-name>com.example.client.app</package-name>
                      <signature-digest>Z2DK...9oKQ=</signature-digest>
                      <android-policy>the-emulator-policy-name</android-policy>
                  </android>
                </attestation>
            </client>
        </config-backed>
    </client-store>
</authorization-server>

Warning

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.

Flow state management

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:

  • The Set-Session-Id response header is used by the server to communicate an opaque identifier to the client application.
  • The Session-Id request header is used by the client to send this opaque identifier on all subsequent requests from the same flow. Note that the server can send new Set-Session-Id headers in the middle of a flow. In that case, the client application must use the newer identifier to complete the flow.

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 used.

SDK

Curity provides a number of SDKs that allow the development of tools to extend and integrate with the Curity Identity Server. See Access to the Curity Release Repository on how to obtain these SDKs.

The following HAAPI SDKs are currently available to help develop client applications that use HAAPI.