Skip to main content

FIDO2 (Authentication)

This is a technical guide on how to implement the FIDO2 authentication by simply following the steps below.

What is FIDO2?

FIDO2 enables users to leverage common devices to easily authenticate to online services in both mobile and desktop environments.

It is one of multiple different authentication methods.

authentication_fido.png

When is a user able to use FIDO2 authentication?

CriteriaExampleConfiguration
User Verification SetupThe user has to log in to the portal and can enroll the FIDO2 using either the cidaas App or any other custom Authenticator App
Allowed Verification MethodsAn app setting to configure FIDO2 authentication as a login method.app-otp

Understanding the Flow and APIs

APIDescriptionLink
Get the configured authentication methodsDisplays the configured authentication methods of a userLink to API
Initiate the authenticationThis API is used to initiate the configured authentications, e.g., when a user clicks on the Backup code authentication, it initiates the Backup code authentication.Link to API
Perform the authenticationAfter successfully authenticating by entering the Backup code, the enrollment completion will finally enroll the user. Link to API
Finish up the authentication and continue loginContinue the login process once the authentication is successful. Link to API

Step 1: Allow FIDO2 in the App settings

In the Admin portal, you need to make the FIDO2 verification type an allowed authentication method under App advanced settings.

To do that,

You can change your existing application, by navigating to Apps -> App Settings -> Edit -> Advanced Settings -> Authentication -> MFA -> Authentication -> FIDO2.

app-otp

Step 2: Rendering the user verification methods

Before initiating the FIDO2 authentication, perform an Authorization (Authz) Call and generate the requestId, then use it in the upcoming API calls.

The first call will be to get the configured verification methods for a user. Based on the response, you provide a selection of verification methods for your user. Below is a demo of how this can look by presenting different verification icons.

Call the configured verification methods of a user. This will filter the user configured verification methods and the app level configuration.

authentication_otps.png

APIDescriptionLink
Get the configured authentication methodsDisplays the configured authentication methods of a userLink to API

This API requires you to provide the user identifier(could be an email, mobile number or any other identifiers) and the requestId. It returns the type as FIDO2 if the user has configured.

Request

curl --location '{{base_url}}/verification-srv/public/graph/user/setup' \
--header 'content-type: application/json' \
--data-raw '{
"request_id": "df08cabb-4b8c-4181-9f6f-f6948802ebf7",
"identifier": "[email protected]"
}'

This will return the list of all verification methods available for the user to authenticate.

Response

{
"success": true,
"status": 200,
"data": {
"configured_list": [
{
"type": "FIDO2"
}
]
}
}

Step 3: Initiating FIDO2 authentication

When the user selects FIDO2 in the list of authentication methods, the initiate API needs to be called. To support cross-domain authentication, you can pass domainURL and allowedDomains in the request body.

Cross-Domain Authentication Support:

  • domainURL: (Optional) The domain URL to be used as the Relying Party ID (RP ID) for FIDO2 cross-domain authentication. This allows you to host enrollment and authentication pages on different domains. The domainURL will be used as the RP ID during both credential creation (registration) and assertion (authentication) phases.

Note: If domainURL is provided

APIDescriptionLink
Initiate the authenticationInitiates the login authentication process via FIDO2 verification methodLink to API

This API initiates the FIDO2 authentication. It returns an exchange_id, status_id, masked sub and fido2_entity having a server challenge which is useful for the Step 4

Request

curl --location '{{base_url}}/verification-srv/authentication/fido2/initiation' \
--header 'content-type: application/json' \
--data-raw '{
"usage_type": "PASSWORDLESS_AUTHENTICATION",
"request_id": "df08cabb-4b8c-4181-9f6f-f6948802ebf7",
"medium_id": "cd7e9166-99d1-4d36-bc8f-3c8ffb2ad011",
"identifier": "[email protected]",
"domainURL": "https://anotherdomain.com"
}'

This will return a status_id, exchange_id, fido2_entity and masked sub which are unique for this process and the following steps will rely on this being provided.

Response

{
"success": true,
"status": 200,
"data": {
"exchange_id": {
"exchange_id": "455fd20d-837d-43a6-a212-a02eeea1a46b",
"expires_at": "2024-01-10T20:45:51.781Z"
},
"medium_text": "[email protected]",
"sub": "6837c08e-d748-4091-8d8e-a3e24f30e0f8",
"status_id": "710792ba-32f9-4d2d-8584-fefa3a6d94b8",
"fido2_entity": {
"type": "LOGIN",
"fidoRequestId": "string",
"server_challenge": {
"challenge": "string",
"rp": {
"id": "string",
"name": "string"
},
"user": {
"id": "string",
"name": "string",
"displayName": "string"
},
"authenticatorSelection": {
"requireResidentKey": false,
"userVerification": "discouraged"
},
"attestation": "none",
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
}
]
}
}
}
}

Step 4: Perform the authentication

When the user completes the FIDO2 authentication, the following API needs to be called.

This API requires you to provide the fido2_client_response (response from browser fido authentication) and exchange_id (exchange id received from Step 3)

APIDescriptionLink
Perform the authenticationComplete the authentication process using the mobile App on FIDO2 authentication method. Link to API

This API performs the authentication when the user completes FIDO authentication in the browser. It returns a new exchange_id and status_id which is required as input for the Step 5.

Request

curl --location '{{base_url}}/verification-srv/authentication/fido2/verification' \
--header 'Content-Type: application/json' \
--data '{
"exchange_id": "455fd20d-837d-43a6-a212-a02eeea1a46b",
"type": "FIDO2",
"fido2_client_response": {
"client_response": {
"rawId": "AY3Orx4_ZM1XVflAy-c4FXJyL",
"response": {
"authenticatorData": "KnpyH6ouogUi",
"signature": "MEUCI",
"userHandle": null,
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY"
},
"authenticatorAttachment": "cross-platform",
"getClientExtensionResults": {},
"id": "AY3Orx4_ZM1XVflAy-c4FXJyL",
"type": "public-key"
},
"fidoRequestId": "ce4ef9e3-43bc-4c5b-a56d-56d926b83ce3"
}
}'

This will return a new exchange_id which is unique for this process and the following steps will rely on this being provided.

Response

{
"success": true,
"status": 200,
"data": {
"exchange_id": {
"exchange_id": "dab51b25-2ae9-4bbe-ad5a-6f1d8c554dd5",
"expires_at": "2024-01-12T08:13:56.052Z"
},
"sub": "6837c08e-d748-4091-8d8e-a3e24f30e0f8",
"status_id": "710792ba-32f9-4d2d-8584-fefa3a6d94b8"
}
}

Step 5: Finish up the login process

Once the user has successfully completed the authentication, finish the login process by calling the following API. This will redirect when the authentication is successful to the provided redirect_uri including a code or an access_token depending on the OAuth2 Flow used. Link to API

curl --location '{{base_url}}/login-srv/verification/login' \
--header 'content-type: application/x-www-form-urlencoded' \
--data-urlencode 'requestId=df08cabb-4b8c-4181-9f6f-f6948802ebf7' \
--data-urlencode 'verificationType=FIDO2' \
--data-urlencode 'sub=6837c08e-d748-4091-8d8e-a3e24f30e0f8' \
--data-urlencode 'status_id=710792ba-32f9-4d2d-8584-fefa3a6d94b8' \
APIDescriptionLink
Continue Login After Passwordless AuthenticationContinue the login process once the authentication is successful. Link to API

Implementation using Javascript SDK

To authenticate the user via FIDO2 using the JavaScript SDK, follow the below steps

To install the cidaas-sdk please perform the following command

npm install cidaas-javascript-sdk

The import to your webapp will be done by using:

const cidaas = new CidaasSDK.WebAuth(options);

Step 1: Rendering the user verification methods

const mfaList = await this.cidaas.getMFAList({
identifier: e.identifier,
request_id: this.route.snapshot.queryParams['requestId'],
});

The UI will be rendered based on this response by displaying all configured verification methods.

Step 2: Initiating a FIDO2 authentication

When the user selects FIDO2 in the list of authentication methods, the initiateMFA method needs to be called.

const payload: IInitiateMFAPayload = {};

// pushIndex is the index of the type FIDO2 in the list and deviceIndex is the index of the device in the mediums list
const medium_id = mfaList[pushIndex]['mediums'][deviceIndex]['id'];

// usage_type should be PASSWORDLESS_AUTHENTICATION or MULTIFACTOR_AUTHENTICATION or INITIAL_AUTHENTICATION
payload['usage_type'] = 'PASSWORDLESS_AUTHENTICATION';

// requestId should come in the login hosted page query param
payload['request_id'] = this.route.snapshot.queryParams['requestId'];

payload['medium_id'] = medium_id;
payload['type'] = this.verificationType;

// Optional: For cross-domain FIDO2 authentication
payload['domainURL'] = 'https://yourdomain.com';

const initResp = await this.cidaas.initiateMFA(payload);

Step 3: Perform the authentication

When the user completes the FIDO2 browser authentication, the authenticateMFA method needs to be called.

function authenticate() {
let publicKey = generatePublicKeyCred(initResp.server_challenge);
this.navigator.credentials.get({ publicKey }).then((response) => {
// create the FIDO2 public key credential, you can use any other methods to generate this public key credential
let publicKeyCredential = publicKeyCredentialToJSON(response);

// setting up the payload for the FIDO2 authentication
const authenticatePayload: any = {
sub: initResp.sub,
exchange_id: initResp.exchange_id.exchange_id,
type: this.verificationType,
fido2_client_response: {
client_response: publicKeyCredential,
fidoRequestId: initResp.fido2_entity.fidoRequestId,
}
};
const authenticateResp = await this.cidaas.authenticateMFA(authenticatePayload);
}
}

function generatePublicKeyCred(serverChallenge) {
// decode base64 string of challenge
serverChallenge.challenge = this.decode(serverChallenge.challenge);
for (let allowCred of serverChallenge.allowCredentials) {
// decode base64 string of credId
allowCred.id = this.decode(allowCred.id);
}
return serverChallenge;
}

function publicKeyCredentialToJSON(pubKeyCred) {
if (pubKeyCred instanceof Array) {
let arr: any = [];
for (let i of pubKeyCred) {
arr.push(this. publicKeyCredentialToJSON(i))
}
return arr;
}
if (pubKeyCred instanceof ArrayBuffer) {
return this.encode(pubKeyCred);
}
if (pubKeyCred instanceof Object) {
let obj = {};
for (let key in pubKeyCred) {
obj[key] = this.publicKeyCredentialToJSON(pubKeyCred[key]);
}
return obj;
}
return pubKeyCred;
}

Step 4: Continue the Login Process

Once the user successfully completed the authentication, finish the login process by calling the passwordlessLogin method. This will redirect to the provided redirect_uri including a code or an access_token depending on the OAuth2 flow used.

let options = {
requestId: this.route.snapshot.queryParams['requestId'],
verificationType: this.verificationType,
sub: this.sub,
status_id: this.status_id
};

this.cidaas.passwordlessLogin(options);

Need Support?

Please contact us directly on our support page.