Example - Using an external browser

Sometimes an Hypermedia Authentication API (HAAPI) flow requires the use of a browser window to be completed. This can happen for two main reasons:

  1. The authentication uses an authenticator or authentication action that is still not adapted to HAAPI.
  2. The authentication uses an external identity provider that requires browser-driven interaction, such as an OpenID Connect provider or a SAML Identity Provider.

Note

The first reason will not be the case by the time HAAPI support is finalized.

To handle this scenario, it is possible for the HAAPI flow to require the creation of a browser window to complete part of the flow. On a native client this may be achieved by using the system browser or one of the methods recommended on RFC 8252. On a browser-based client, a solution is to open a separate window or tab, so that the client doesn’t loose its state.

To illustrate how this is achieved, in this section we describe a flow using an external SAML identity provider.

The initial part is similar to the previous examples and we will not be showing it here: the client starts with an authorization request, is redirected to the authentication service and receives an authenticator selection representation.

If the user selects a SAML authenticator, then the client performs a GET request to the associated href:

GET /dev/authn/authenticate/saml1 HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...-g
DPoP: ey...ww

The response is an authentication step containing the special client-operation action:

HTTP/1.1 200 OK
Content-Type: application/vnd.auth+json

{
  "type": "authentication-step",
  "actions": [
    {
      "template": "client-operation",
      "kind": "external-browser",
      "title": "The authentication process needs to use an external browser",
      "model": {
        "name": "external-browser-flow",
        "arguments": {
          "href": "https://localhost:8443/dev/authn/authenticate/saml1?_launch_nonce=Gxs557NFwUTe5kwH8GjFK3MENoQVbHLe",
        },
        "continueActions": [
          {
            "template": "form",
            "kind": "continue",
            "title": "If you are not redirected automatically, click here to continue authenticating",
            "model": {
              "href": "https://localhost:8443/dev/authn/authenticate/saml1",
              "method": "GET",
              "type": "application/x-www-form-urlencoded",
              "fields": [
                {
                  "name": "_resume_nonce",
                  "type": "context"
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

It is the presence of this client-operation action with the name field, present inside model, set to external-browser-flow that signals to the client that an external browser needs to be used to continue with the flow. The action’s href field, present inside arguments, contains the URL where the browser window should be opened. The client should react to the previous response by opening a browser window/tab to that URL, eventually after requesting permission from the user and showing the action’s title string.

The client then needs to wait until the external browser sub-flow is completed before resuming the HAAPI flow, using the action inside continueActions. That is triggered by the browser sending a nonce back to the client, which is then used as the source for the context field in the continuation action. The way this information is passed back to the client depends on the client type.

On a native client, the browser can be redirected to the application by using an HTTP URI or a custom scheme URI associated to the application. The nonce will then be present in the query string. The redirect URI needs to be registered for the client and also needs to be passed on the browser launch’s URL (see redirect_uri query-string parameter):

https://example.com/dev/authn/authenticate/saml1?_launch_nonce=cE...EB&redirect_uri=https://client.example.net/client-callback

On a browser-based client, the external window posts a message (via postMessage) to the opener window, i.e., the window where the HAAPI client is running. The nonce will be present in that message. This means that the client application, i.e. the opener window, can receive the nonce via an event listener for the message type. To trigger this behavior, the for_origin needs to be passed on the browser launch’s URL:

https://example.com/dev/authn/authenticate/saml1?_launch_nonce=cE...EB&for_origin=https://client.example.net

In this case, the client should also validate the nonce’s origin, namely the postMessage source window.

Upon receiving the nonce, the client performs the action inside continueActions, using the nonce as the source for the context type field:

GET dev/authn/authenticate/saml1?_resume_nonce=t9...kH HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...-g
DPoP: ey...1A

If this SAML authenticator is the only one required authenticator, then the authentication process is completed and the response is a redirect back to the token service:

HTTP/1.1 200 OK
Content-Type: application/vnd.auth+json

{
  "type": "authentication-step",
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model":{
        "href": "/dev/oauth/authorize?client_id\u003dhaapi-client",
        "method": "POST",
        "type": "application/x-www-form-urlencoded",
        "title": "Login",
        "actionTitle": "Please click this button if you are not redirected",
        "fields": [
          {
            "name": "token",
            "type": "hidden",
            "value": "xk...5s"
          },
          {
            "name": "state",
            "type": "hidden",
            "value": "R_...SX"
          }
        ]
      }
    }
  ]
}

When following this last redirect:

POST /dev/oauth/authorize?... HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Content-Type: application/x-www-form-urlencoded
Authorization: DPoP ey...6w
DPoP: ey...Kg

token=...&state=...

The response is an authorization response, similar to the one described in the previous examples:

HTTP/1.1 200 OK
Content-Type: application/vnd.auth+json

{
  "type": "oauth-authorization-response",
  "properties": {
    "code": "3H...h3",
    "state":"..."
  },
  "links": [
    {
      "href": "https://client.example.net/client-callback?code\u003d3H...h3\u0026state\u003d...",
      "rel": "authorization-response"
    }
  ]
}