Example - Encap authentication with device registration

This section describes the sequence of requests and responses for a more complex Hypermedia Authentication API (HAAPI) flow, this time based on the Encap authenticator. It illustrates different interaction scenarios, namely device registration and polling for authentication completion.

The initial part is similar to the previous example 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 the Encap authenticator, then the client must perform a GET request to the associated href:

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

The response has one action, containing a form with a single field to collect the user’s name:

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

{
  "type": "authentication-step",
  "actions": [
    {
      "template": "form",
      "kind": "login",
      "title": "Enter Username",
      "model": {
        "href": "/dev/authn/authenticate/encap1",
        "method": "POST",
        "type": "application/x-www-form-urlencoded",
        "actionTitle": "Authenticate",
        "fields": [
          {
            "name": "userName",
            "type": "username",
            "label": "Enter your username"
          }
        ]
      }
    }
  ]
}

The client should obtain the name from the user and perform the associated POST request.

Request:

POST /dev/authn/authenticate/encap1 HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Content-Type: application/x-www-form-urlencoded
Authorization: DPoP ey...8g
DPoP: ey...Kg

userName=testuser

If the user name is accepted, then the response is a redirect to the select device step:

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

{
  "type": "redirection-step",
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model": {
        "href": "https://localhost:8443/dev/authn/authenticate/encap1/select-device",
        "method": "GET"
      }
    }
  ]
}

We emphasize that this redirect behavior should not be hard-coded into the client application. Instead, the client should just follow the HAAPI instructions:

GET /dev/authn/authenticate/encap1/select-device HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...8g
DPoP: ey...0Q

The result response is:

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

{
  "type": "authentication-step",
  "messages": [
    {
      "text": "No devices have been associated with this user.",
      "classList": [
        "warn"
      ]
    }
  ],
  "links": [
    {
      "href": "/dev/authn/anonymous/encap1",
      "rel": "register-create",
      "title": "Add another Device"
    }
  ]
}

This response illustrates another feature of HAAPI representations: user messages. The optional messages field contains a list of objects, where each one has two fields:

  • text is an UI-ready string containing a message to the user, such as an information or a warning.
  • classList is a list of classes, with at least one element, classifying the message purpose. In the previous example, the message is a warning, informing the user that no devices are associated with their account and therefore a registration is probably required.

Since in this example the user doesn’t have any registered devices, the response representation contains only a single link to the device registration flow, as identified by the register-create link relation. Later in this section we will see how this response would look like if there were registered devices. The client should react to this response by presenting this option to the user. If the user selects it, then a GET request to the associated href should be performed:

GET /dev/authn/anonymous/encap1 HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...0w
DPoP: ey...0Q

The response has registrations-step type to clearly indicate that we are now in a registration flow. It contains informational links and a single action with a continue kind. This kind is commonly used to annotate the action that should be used to continue the current flow, tipically without requiring any extra information from the user:

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

{
  "links": [
    {
      "href": "https://www.encapsecurity.com/Twobo.html",
      "rel": "download"
    },
    {
      "href": "data:image/png;base64,iV...gg==",
      "rel": "download"
    }
  ],
  "type": "registration-step",
  "actions": [
    {
      "template": "form",
      "kind": "continue",
      "title": "Activate Device",
      "model": {
        "href": "/dev/authn/register/create/encap1",
        "method": "GET",
        "type": "application/x-www-form-urlencoded",
        "actionTitle": "Activate Device"
      }
    }
  ]
}

A client will probably react to this representation by showing an informational screen with a continue UI control. When the user selects it, the client does the request described by the form:

GET /dev/authn/register/create/encap1 HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...Gg
DPoP: ey...0Q

The response is a redirect to the configured registration authentication method, because the user needs to be authenticated using a secondary method before registering a device:

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

{
  "type": "redirection-step",
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model": {
        "href": "https://localhost:8443/dev/authn/authenticate/group1?__resumeUrl\u003dhttps%3A%2F%2Flocalhost%3A8443%2Fdev%2Fauthn%2Fregister%2Fcreate%2Fencap1\u0026forceAuthN\u003dfalse",
        "method": "GET"
      }
    }
  ]
}

Here, a nested authentication flow will start in order to authenticate the user, such as one using username and password based authentication. When this nested flow ends, HAAPI redirects the client back to the device registration step:

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

{
  "type": "redirection-step",
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model": {
        "href": "https://localhost:8443/dev/authn/register/create/encap1",
        "method": "GET"
      }
    }
  ]
}

When the client follows this request:

GET /dev/authn/register/create/encap1 HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...hw
DPoP: ey...0Q

it gets a representation containing the device registration step:

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

{
  "messages": [
    {
      "text": "Pair device",
      "classList": [
        "info",
        "heading"
      ]
    },
    {
      "text": "To activate a new device, enter the code into your mobile authentication application or use that app to scan the following QR code. Also, enter an alias, phone number or asset number, and select the type of device, so that you can more easily identify it later when logging in.",
      "classList": [
        "info"
      ]
    },
    {
      "text": "245857",
      "classList": [
        "info",
        "activationCode"
      ]
    }
  ],
  "links": [
    {
      "href": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AQAAAACgl2eQAAAA00lEQVR42u3YSw7DIAwEUG7uOVpv5pbPYFREVHXJmEhUTd5qBHZI8efxKgkSJEiQ4AeA0oYh5s+vILA+84p7agA1oPmo/xMGbZ0kmMtGFpDV+08763LAQmojpmOlvRvMAT44dd67AWrZGLXDxj76SlID9HKBlUEQOHeLLZG5HsDcLS0r67MgYDNlTFsB0QAeMY3lcmgol4PZSrlStgojAmypIuZxGpMDPIhx62BrrErAEUFpAyoWUzWwvm6VyEkNrAexFhIeTmr3gvxenSBBggR/gzcXVJvkxInWqQAAAABJRU5ErkJggg==",
      "rel": "activation"
    }
  ],
  "type": "registration-step",
  "actions": [
    {
      "template": "form",
      "kind": "device-register",
      "title": "Activate",
      "model": {
        "href": "/dev/authn/register/create/encap1",
        "method": "POST",
        "type": "application/x-www-form-urlencoded",
        "actionTitle": "Pair device",
        "fields": [
          {
            "name": "activationCode",
            "type": "hidden",
            "value": "245857"
          },
          {
            "name": "alias",
            "type": "text",
            "label": "Device Alias"
          },
          {
            "name": "number",
            "type": "text",
            "label": "Phone Number / Asset ID"
          },
          {
            "name": "devicetype",
            "type": "select",
            "label": "Device Type",
            "options": [
              {
                "value": "phone",
                "label": "Phone"
              },
              {
                "value": "tablet",
                "label": "Tablet"
              },
              {
                "value": "other",
                "label": "Other"
              }
            ]
          }
        ]
      }
    }
  ]
}

Notice:

  • The presence of multiple user messages providing contextual information to the user. The client can use the provided classes (e.g. heading, activationCode) to customize the UI presentation (e.g. showing the message with activationCode in a bigger font, or using the heading class to define the UI screen title).
  • The response also contains a form to collect the registration information, such as the device alias, device number and device type. For this last information item, the form uses a field with the select type.

After collecting all this information, the client performs the associated POST:

POST /dev/authn/authenticate/encap1 HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Content-Type: application/x-www-form-urlencoded
Authorization: DPoP ey...ow
DPoP: ey...Kg

activationCode=407379&alias=the+device+alias&number=123456789&devicetype=phone

If the activation is successful, then the response provides that information:

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

{
  "messages": [
    {
      "text": "Your device has been activated, and you can now use it to start logging into web sites and applications.",
      "classList": [
        "info"
      ]
    }
  ],
  "type": "registration-step",
  "actions": [
    {
      "template": "form",
      "kind": "continue",
      "title": "Continue to activate your device",
      "model": {
        "href": "/dev/authn/authenticate/encap1/select-device",
        "method": "GET"
      }
    }
  ]
}

Once again, the representation contains an action describing the request to perform in order to continue the flow, i.e., go back to the device selection step:

GET /dev/authn/authenticate/encap1/select-device HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...DA
DPoP: ey...Kg

Now the select device response also contains an action, in addition to the add another device link:

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

{
  "links": [
    {
      "href": "/dev/authn/anonymous/encap1",
      "rel": "register-create",
      "title": "Add another Device"
    }
  ],
  "type": "authentication-step",
  "actions": [
    {
      "template": "form",
      "kind": "device-option",
      "title": "Device Selection",
      "model": {
        "href": "/dev/authn/authenticate/encap1/select-device",
        "method": "POST",
        "type": "application/x-www-form-urlencoded",
        "actionTitle": "Device Selection",
        "fields": [
          {
            "name": "device_id",
            "type": "select",
            "label": "Device Selection",
            "options": [
              {
                "value": "873aec5b-c41f-47c8-9a8e-2a93ee40b1f9",
                "label": "the device alias (123456789)"
              }
            ]
          }
        ]
      }
    }
  ]
}

This action contains a form with a select field with one option per registered device. If the user selects one of these devices, the client performs the associated POST request:

POST /dev/authn/authenticate/encap1/select-device HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Content-Type: application/x-www-form-urlencoded
Authorization: DPoP ey...dg
DPoP: ey...Kg

device_id=873aec5b-c41f-47c8-9a8e-2a93ee40b1f9

The response is a redirect to the polling step:

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

{
  "type":"redirection-step",
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model": {
        "href": "https://localhost:8443/dev/authn/authenticate/encap1/wait",
        "method": "GET"
      }
    }
  ]
}

When this redirect is followed by the client:

GET /dev/authn/authenticate/encap1/wait HTTP/1.1
Host: example.com
Accept: application/vnd.auth+json
Authorization: DPoP ey...rA
DPoP: ey...Kg

the response is a polling-step response:

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

{
  "type": "polling-step",
  "properties": {
    "status": "pending"
  },
  "actions": [
    {
      "template": "form",
      "kind": "poll",
      "model": {
        "href": "/dev/authn/authenticate/encap1/wait",
        "method": "GET"
      }
    }
  ]
}

Notice that the type is polling-step, meaning that this is a special authentication step where polling must be performed to wait for some external event to happen. Notice also that the status property is pending, meaning that the polling is not yet completed. In this case there will be an action with the poll kind, describing the request to perform in order to poll the server. The client should perform a periodic request using that action, until the status is not pending anymore:

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

{
  "type": "polling-step",
  "properties": {
    "status": "done"
  },
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model": {
        "href": "/dev/authn/authenticate/encap1/wait",
        "method": "POST",
        "type": "application/x-www-form-urlencoded",
        "fields": [
          {
            "name": "_postback",
            "type": "hidden",
            "value": "true"
          }
        ]
      }
    }
  ]
}

When polling is complete, in addition to the done status, there will be an action that the client should follow, with the redirect kind.

POST /dev/authn/authenticate/encap1/wait HTTP/1.1 Host: example.com Accept: application/vnd.auth+json Content-Type: application/x-www-form-urlencoded Authorization: DPoP ey…dg DPoP: ey…IA

_postback=true

The response is a redirect back to the authorization service, because the authentication was completed successfully:

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

{
  "type": "redirection-step",
  "actions": [
    {
      "template": "form",
      "kind": "redirect",
      "model": {
        "href": "/dev/oauth/authorize?client_id=haapi-public-client",
        "method": "POST",
        "type": "application/x-www-form-urlencoded",
        "fields": [
          {
            "name": "token",
            "type": "hidden",
            "value": "pm...mG"
          },
          {
            "name": "state",
            "type": "hidden",
            "value": "R_T0...ow"
          }
        ]
      }
    }
  ]
}

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...KA
DPoP: ey...Kg

token=...&state=...

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

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

{
  "type": "oauth-authorization-response",
  "properties": {
    "code": "rH...BV",
    "state":"..."
  },
  "links": [
    {
      "href": "https://client.example.net/client-callback?code\u003dbU...oQ\u0026state\u003d...",
      "rel": "authorization-response"
    }
  ]
}