--- title: "Test User Authentication with the FIDO2 Sample Relying Party Web App" slug: "oca-ig-test-user-authentication-with-the-fido2-sample-relying-party-web-app" updated: 2025-07-04T10:09:40Z published: 2025-07-08T14:14:51Z canonical: "docs.onespan.com/oca-ig-test-user-authentication-with-the-fido2-sample-relying-party-web-app" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.onespan.com/llms.txt > Use this file to discover all available pages before exploring further. # Test User Authentication with the FIDO2 Sample Relying Party Web App You can use the FIDO2 Sample Relying Party Web App to test the user authentication flow. ## Authentication flow code samples > The code samples in this article do NOT contain actual production code, rather, the examples used here serve to demonstrate how to integrate FIDO2 into your website. ### Initialization To initialize the authentication process, the user must enter their user name in the AUTHENTICATE tab of the FIDO2 Sample Relying Party Web App, select the respective userVerification option, and click SEND. When authentication is triggered, the FIDO2 Sample Relying Party Web App sends an authentication initialization request to the OneSpan Trusted Identity platform API via the following endpoint: - [POST /users/{userID@domain}/generate-fido-authentication-request](https://community.onespan.com/products/onespan-cloud-authentication/sandbox#/FIDO Authentication/generateFidoAuthenticationRequest) The exact structure of the request body can be verified on the [Platform API Sandbox](https://community.onespan.com/products/onespan-cloud-authentication/sandbox) page. The authInitializationResponse should look like this: ```plaintext {   "authenticationRequest": "{\"challenge\":\"acL8XO3TGqxZM4ZkSk0OZ_FTHsuv50H7Ebik8aX7e7a4RecqoAC_rifHO3BpThUTFtqw8iZZWhXmLhAravNT5g\",\"timeout\":1002,\"rpId\":\"test.onespan.com\",\"allowCredentials\":[{\"type\":\"public-key\",\"id\":\"obF6k-RPAE3GnN6iChWW7O28eEhkKDm5QAFivlY6b5Y\"}],\"userVerification\":\"preferred\",\"extensions\":{\"appId\":\"test\",\"txAuthSimple\":\"test string\",\"txAuthGeneric\":{\"contentType\":\"image/png\",\"content\":\"YWE\"},\"location\":true,\"uvi\":false,\"uvm\":false}}",   "requestID": "authentication:d76814dc-e3ba-429b-96de-7087df26a228" } ``` ### Communication with the client platform During the authentication operation, the user must prove that they own the private key they used in the registration step. Therefore, the user must provide an assertion, which is generated by calling navigator.credentials.get() on the client-side JavaScript of your website. This retrieves the credentials that were generated in the registration operation, along with a signature ```plaintext navigator.credentials.get(publicKeyCredentialRequestOptions); ``` The publicKeyCredentialRequestOptions object should be based on the response received from the initialization step. ```plaintext var resp = JSON.parse(authInitializationResponse.authenticationRequest); var publicKeyCredentialRequestOptions = {   publicKey: {     rp: resp.rp,     challenge: bufferDecode(resp.challenge),     allowCredentials: decodeAllowCredentials(resp.allowCredentials),     timeout: resp.timeout,     userVerification: resp.userVerification,     extensions: resp.extensions   } }; ``` The bufferDecode function is defined in the following way: ```plaintext function bufferDecode(value) {   const s = base64DecodeUrl(value);   const s1 = atob(s);   return Uint8Array.from(s1, c => c.charCodeAt(0)); } function base64DecodeUrl(str) {   str = str + Array((4 - str.length % 4) % 4 + 1).join('=');   return str.replace(/-/g, '+').replace(/_/g, '/'); } ``` The decodeAllowCredentials function is defined in the following way: ```plaintext function decodeAllowCredentials(value) {   if(value!== undefined){     return value.map(ac => {       return {         type: ac.type,         id: bufferDecode(ac.id)       }     })   }   return {}; } ``` The navigator.credentials.get() returns a promise with the PublicKeyCredential object. ```plaintext navigator.credentials.get(credentialAuthenticatorAssertionData)   then(publicKeyCredential => {     finalize(publicKeyCredential); })   catch(e => {     // error handling }); ``` ### Finalization In the finalization step, a POST request is sent to the OneSpan Trusted Identity platform API with the following endpoint: - [POST /users/{userID@domain}/login](https://community.onespan.com/products/onespan-cloud-authentication/sandbox#/Users/loginUsingPOST) The body is prepared based on the previously received PublicKeyCredential object. This request contains the following body: ```plaintext const authenticationResponse = {   id: publicKeyCredential.id,   rawId: toBase64Url(publicKeyCredential.rawId),   type: "public-key",         "authenticatorData": toBase64Url(publicKeyCredential.response.authenticatorData),         "signature": toBase64Url(publicKeyCredential.response.signature),         "userHandle": toBase64Url(publicKeyCredential.response.userHandle),         "clientDataJSON": toBase64Url(publicKeyCredential.response.clientDataJSON)(publicKeyCredential.response.attestationObject),       }     };      const body = {   credentials: {     fidoAuthenticator: {       fidoProtocol: null,       requestID: null,       authenticationResponse: JSON.stringify(authenticationResponse)    }   },   requestID: "c7922f36-5419-4658-84fb-8c9a8ebda168"}; function toBase64Url(arrayBuffer) {   let binary = '';   const bytes = new Uint8Array(arrayBuffer);   const len = arrayBuffer.byteLength;   for (let i = 0; i < len; i++) {   binary += String.fromCharCode(bytes[i]); }   return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); } ``` > The value of the requestID in the body should match the value of the requestID that was retrieved from the authInitializationResponse. For more information on the structure, refer to the [World Wide Web Consortium (W3C) Web Authentication documentation](https://www.w3.org/TR/2019/REC-webauthn-1-20190304/).