---
title: Check Assertion (FIDO Device)
description: The multi-factor authentication flow for a FIDO device checks the authenticator assertion response, which contains the signed challenge needed to complete the MFA flow. The MFA actions service validates the challenge.
component: pingone-api
page_id: pingone-api:mfa:mfa-authentication/mfa-device-authentications/check-assertion-device-authentication
canonical_url: https://developer.pingidentity.com/pingone-api/mfa/mfa-authentication/mfa-device-authentications/check-assertion-device-authentication.html
section_ids:
  device-authentication: Device authentication
  prerequisites: Prerequisites
  headers: Headers
  body: Body
  example-request: Example Request
---

# Check Assertion (FIDO Device)

##

```none
POST {{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}
```

The multi-factor authentication flow for a FIDO device checks the authenticator assertion response, which contains the signed challenge needed to complete the MFA flow. The MFA actions service validates the challenge.

The following sample shows the `POST /{{envID}}/deviceAuthentications/{{deviceAuthID}}` operation to validate the assertion used in the multi-factor authentication flow. This operation uses the `application/vnd.pingidentity.assertion.check+json` custom media type as the content type in the request header.

|   |                                                                                                                                                                                                                                                                                                           |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The `ASSERTION_REQUIRED` flow state includes the `publicKeyCredentialRequestOptions` response property that specifies the public key credential request options object generated for the selected device that is used to call the `navigator.credentials.get()` on the browser to generate the assertion. |

### Device authentication

A FIDO2 biometrics device flow uses functions from the Web Authentication API (webauthn API) to manage device authentication. The following sample JavaScript code will help you implement the webauthn API for browser-based operations.

For more information about the Web Authentication API, refer to [Web Authentication: An API for accessing Public Key Credentials](https://www.w3.org/TR/webauthn/).

Call the `navigator.credentials.get` method using the `publicKeyCredentialOptions` returned from the `assertion.check` action of the Flows service (refer to [Assertion Check](/pingone/auth/v1/api/#post-check-assertion)). As an example, refer to the `WebAuthnAuthentication` function in the following code sample:

```none
var authAbortController = window.PublicKeyCredential ? new AbortController() : null;
var authAbortSignal = window.PublicKeyCredential ? authAbortController.signal : null;

window.abortWebAuthnSignal = function abortWebAuthnSignal() {
    authAbortController.abort();
    authAbortController = new AbortController();
    authAbortSignal = authAbortController.signal;
}

window.IsWebAuthnSupported = function IsWebAuthnSupported() {
    if (!window.PublicKeyCredential) {
        console.log("Web Authentication API is not supported on this browser.");
        return false;
    }
    return true;
}

window.isWebAuthnPlatformAuthenticatorAvailable = function isWebAuthnPlatformAuthenticatorAvailable() {
    var timer;
    var p1 = new Promise(function(resolve) {
        timer = setTimeout(function() {
            resolve(false);
        }, 1000);
    });
    var p2 = new Promise(function(resolve) {
        if (IsWebAuthnSupported() && window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable) {
            resolve(
	            window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().catch(function(err) {
                    console.log(err);
                    return false;
                }));
        }
        else {
            resolve(false);
        }
    });
    return Promise.race([p1, p2]).then(function (res) {
        clearTimeout(timer);
        console.log("isWebAuthnPlatformAuthenticatorAvailable - " +  res);
        return res;
    });
}

window.WebAuthnPlatformAuthentication = function WebAuthnPlatformAuthentication(publicKeyCredentialRequestOptions) {
    return new Promise(function(resolve, reject) {
        isWebAuthnPlatformAuthenticatorAvailable().then(function (result) {
            if (result) {
                resolve(Authenticate(publicKeyCredentialRequestOptions));
            }
            reject(Error("UnSupportedBrowserError"));
        });
    });
}

function Authenticate(publicKeyCredentialRequestOptions) {
    return new Promise(function(resolve, reject) {
        var options = JSON.parse(publicKeyCredentialRequestOptions);
        var publicKeyCredential = {};
        publicKeyCredential.challenge = new Uint8Array(options.challenge);
        if ('allowCredentials' in options) {
            publicKeyCredential.allowCredentials = credentialListConversion(options.allowCredentials);
        }
        if ('rpId' in options) {
            publicKeyCredential.rpId = options.rpId;
        }
        if ('timeout' in options) {
            publicKeyCredential.timeout = options.timeout;
        }
        if ('userVerification' in options) {
            publicKeyCredential.userVerification = options.userVerification;
        }
        console.log(publicKeyCredential);
        navigator.credentials.get({"publicKey": publicKeyCredential})
            .then(function (assertion) {
                // Send new credential info to server for verification and registration.
                console.log(assertion);
                var publicKeyCredential = {};
                if ('id' in assertion) {
                    publicKeyCredential.id = assertion.id;
                }
                if ('rawId' in assertion) {
                    publicKeyCredential.rawId = toBase64Str(assertion.rawId);
                }
                if ('type' in assertion) {
                    publicKeyCredential.type = assertion.type;
                }
                var response = {};
                response.clientDataJSON = toBase64Str(assertion.response.clientDataJSON);
                response.authenticatorData = toBase64Str(assertion.response.authenticatorData);
                response.signature = toBase64Str(assertion.response.signature);
                response.userHandle = toBase64Str(assertion.response.userHandle);
                publicKeyCredential.response = response;
                resolve(JSON.stringify(publicKeyCredential));
            }).catch(function (err) {
            // No acceptable authenticator or user refused consent. Handle appropriately.
            console.log(err);
            reject(Error(err.name));
        });
    });
}

function credentialListConversion(list) {
    var credList = [];
    for (var i=0; i < list.length; i++) {
        var cred = {
            type: list[i].type,
            id: new Uint8Array(list[i].id)
        };
        if (list[i].transports) {
            cred.transports = list[i].transports;
        }
        credList.push(cred);
    }
    return credList;
}

function toBase64Str(bin){
    return btoa(String.fromCharCode.apply(null, new Uint8Array(bin)));
}

const isWebAuthnSupported = () => {
  if (!window.PublicKeyCredential) {
    return false;
  }
  return true;
};

function getCompatibility() {
  return isWebAuthnPlatformAuthenticatorAvailable()
      .then((result) => {
        if (result) {
          return 'FULL';
        } else if (isWebAuthnSupported()) {
          return 'SECURITY_KEY_ONLY';
        } else {
          return 'NONE';
        }
      })
      .catch(() => {
        if (isWebAuthnSupported()) {
          return 'SECURITY_KEY_ONLY';
        } else {
          return 'NONE';
        }
      });
}
```

#### Prerequisites

* [Initialize device authentication](#post-initialize-device-authentication) to get a `{{deviceAuthID}}` for the endpoint. For more information, refer to [MFA Device Authentications](#mfa-device-authentications).

> **Collapse: Request Model**
>
> | Property        | Type   | Required? |
> | --------------- | ------ | --------- |
> | `origin`        | String | Required  |
> | `assertion`     | String | Required  |
> | `compatibility` | String | Optional  |
>
> Refer to the [Device authentications](#device-authentications-data-model) data model for full property descriptions.

### Headers

Authorization      Bearer {{accessToken}}

Content-Type      application/vnd.pingidentity.assertion.check+json

### Body

raw ( application/vnd.pingidentity.assertion.check+json )

```json
{
    "origin": "https://app.pingone.com",
    "assertion": "{{assertionFromBrowser}}",
    "compatibility" : "FULL"
}
```

##

### Example Request

* cURL

* C#

* Go

* HTTP

* Java

* jQuery

* NodeJS

* Python

* PHP

* Ruby

* Swift

```shell
curl --location --globoff '{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}' \
--header 'Content-Type: application/vnd.pingidentity.assertion.check+json' \
--header 'Authorization: Bearer {{accessToken}}' \
--data '{
    "origin": "https://app.pingone.com",
    "assertion": "{{assertionFromBrowser}}",
    "compatibility" : "FULL"
}'
```

```csharp
var options = new RestClientOptions("{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}")
{
  MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("", Method.Post);
request.AddHeader("Content-Type", "application/vnd.pingidentity.assertion.check+json");
request.AddHeader("Authorization", "Bearer {{accessToken}}");
var body = @"{" + "\n" +
@"    ""origin"": ""https://app.pingone.com""," + "\n" +
@"    ""assertion"": ""{{assertionFromBrowser}}""," + "\n" +
@"    ""compatibility"" : ""FULL""" + "\n" +
@"}";
request.AddStringBody(body, DataFormat.Json);
RestResponse response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);
```

```golang
package main

import (
  "fmt"
  "strings"
  "net/http"
  "io"
)

func main() {

  url := "{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}"
  method := "POST"

  payload := strings.NewReader(`{
    "origin": "https://app.pingone.com",
    "assertion": "{{assertionFromBrowser}}",
    "compatibility" : "FULL"
}`)

  client := &http.Client {
  }
  req, err := http.NewRequest(method, url, payload)

  if err != nil {
    fmt.Println(err)
    return
  }
  req.Header.Add("Content-Type", "application/vnd.pingidentity.assertion.check+json")
  req.Header.Add("Authorization", "Bearer {{accessToken}}")

  res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

  body, err := io.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
```

```http
POST /{{envID}}/deviceAuthentications/{{deviceAuthID}} HTTP/1.1
Host: {{authPath}}
Content-Type: application/vnd.pingidentity.assertion.check+json
Authorization: Bearer {{accessToken}}

{
    "origin": "https://app.pingone.com",
    "assertion": "{{assertionFromBrowser}}",
    "compatibility" : "FULL"
}
```

```java
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("application/vnd.pingidentity.assertion.check+json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"origin\": \"https://app.pingone.com\",\n    \"assertion\": \"{{assertionFromBrowser}}\",\n    \"compatibility\" : \"FULL\"\n}");
Request request = new Request.Builder()
  .url("{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}")
  .method("POST", body)
  .addHeader("Content-Type", "application/vnd.pingidentity.assertion.check+json")
  .addHeader("Authorization", "Bearer {{accessToken}}")
  .build();
Response response = client.newCall(request).execute();
```

```javascript
var settings = {
  "url": "{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}",
  "method": "POST",
  "timeout": 0,
  "headers": {
    "Content-Type": "application/vnd.pingidentity.assertion.check+json",
    "Authorization": "Bearer {{accessToken}}"
  },
  "data": JSON.stringify({
    "origin": "https://app.pingone.com",
    "assertion": "{{assertionFromBrowser}}",
    "compatibility": "FULL"
  }),
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
```

```javascript
var request = require('request');
var options = {
  'method': 'POST',
  'url': '{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}',
  'headers': {
    'Content-Type': 'application/vnd.pingidentity.assertion.check+json',
    'Authorization': 'Bearer {{accessToken}}'
  },
  body: JSON.stringify({
    "origin": "https://app.pingone.com",
    "assertion": "{{assertionFromBrowser}}",
    "compatibility": "FULL"
  })

};
request(options, function (error, response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
```

```python
import requests
import json

url = "{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}"

payload = json.dumps({
  "origin": "https://app.pingone.com",
  "assertion": "{{assertionFromBrowser}}",
  "compatibility": "FULL"
})
headers = {
  'Content-Type': 'application/vnd.pingidentity.assertion.check+json',
  'Authorization': 'Bearer {{accessToken}}'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)
```

```php
<?php
require_once 'HTTP/Request2.php';
$request = new HTTP_Request2();
$request->setUrl('{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}');
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setConfig(array(
  'follow_redirects' => TRUE
));
$request->setHeader(array(
  'Content-Type' => 'application/vnd.pingidentity.assertion.check+json',
  'Authorization' => 'Bearer {{accessToken}}'
));
$request->setBody('{\n    "origin": "https://app.pingone.com",\n    "assertion": "{{assertionFromBrowser}}",\n    "compatibility" : "FULL"\n}');
try {
  $response = $request->send();
  if ($response->getStatus() == 200) {
    echo $response->getBody();
  }
  else {
    echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' .
    $response->getReasonPhrase();
  }
}
catch(HTTP_Request2_Exception $e) {
  echo 'Error: ' . $e->getMessage();
}
```

```ruby
require "uri"
require "json"
require "net/http"

url = URI("{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}")

http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Post.new(url)
request["Content-Type"] = "application/vnd.pingidentity.assertion.check+json"
request["Authorization"] = "Bearer {{accessToken}}"
request.body = JSON.dump({
  "origin": "https://app.pingone.com",
  "assertion": "{{assertionFromBrowser}}",
  "compatibility": "FULL"
})

response = http.request(request)
puts response.read_body
```

```swift
let parameters = "{\n    \"origin\": \"https://app.pingone.com\",\n    \"assertion\": \"{{assertionFromBrowser}}\",\n    \"compatibility\" : \"FULL\"\n}"
let postData = parameters.data(using: .utf8)

var request = URLRequest(url: URL(string: "{{authPath}}/{{envID}}/deviceAuthentications/{{deviceAuthID}}")!,timeoutInterval: Double.infinity)
request.addValue("application/vnd.pingidentity.assertion.check+json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer {{accessToken}}", forHTTPHeaderField: "Authorization")

request.httpMethod = "POST"
request.httpBody = postData

let task = URLSession.shared.dataTask(with: request) { data, response, error in
  guard let data = data else {
    print(String(describing: error))
    return
  }
  print(String(data: data, encoding: .utf8)!)
}

task.resume()
```
