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:
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.
POST
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:
messages
text
classList
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:
register-create
GET
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:
registrations-step
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:
heading
activationCode
select
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:
polling-step
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:
type
status
pending
poll
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.
done
redirect
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
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" } ] }