vivshankar / adaptive-proxy-sdk-javascript

This library is to provide an interface for device authentication, authorization, and risk assessment using IBM Security Verify.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

IBM Security Verify Adaptive Proxy SDK for JavaScript

The Proxy SDK for server-side JavaScript (Node). The purpose of this library is to provide an interface for device authentication, authorization, and risk assessment using IBM Security Verify.

Prerequisites

Installation

Use npm to install the Proxy SDK:

npm install adaptive-proxy-sdk

Configuration Settings

To use the Proxy SDK, you will need to initialise an Adaptive object with a configuration object. The configuration object should contian the following parameters:

Parameter Type Description
tenantUrl string The base URL of your IBM Security Verify Tenant
clientId string The identifier of your Security Verify application
clientSecret string The secret for your Security Verify application

See Initialise an Adaptive object for an example.

Context Object

A call to each function in this SDK requires a context object as a parameter. This context object contains information about the user-agent attempting the request, such as a session identifier. This device-related information will be used to assess risk during each request.

The context object should contain the following parameters:

Parameter Type Description
sessionId string The session ID generated by the user-agent, using an Adaptive client SDK.
userAgent string The user-agent, typically obtained from the User-Agent HTTP header.
ipAddress string The IP address of the user-agent.

Overview

Function Async Return
assessPolicy(context) Promise<Object>
lookupIdentitySources(context, transactionId, [sourceName] Promise<Object>
evaluatePassword(context, transactionId, identitySourceId, username, password) Promise<Object>
generateFIDO(context, transactionId, relyingPartyId, userId) Promise<Object>
evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON) Promise<Object>
generateQR(context, transactionId, profileId) Promise<Object>
evaluateQR(context, transactionId) Promise<Object>
generateEmailOTP(context, transactionId, enrollmentId) Promise<Object>
generateSMSOTP(context, transactionId, enrollmentId) Promise<Object>
generateVoiceOTP(context, transactionId, enrollmentId) Promise<Object>
evaluateTOTP(context, transactionId, enrollmentId, otp) Promise<Object>
evaluateEmailOTP(context, transactionId, otp) Promise<Object>
evaluateSMSOTP(context, transactionId, otp) Promise<Object>
evaluateVoiceOTP(context, transactionId, otp) Promise<Object>
generateQuestions(context, transactionId, enrollmentId) Promise<Object>
evaluateQuestions(context, transactionId, questions) Promise<Object>
generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData) Promise<Object>
evaluatePush(context, transactionId) Promise<Object>
getToken(transactionId) String
logout(accessToken) undefined
refresh(context, refreshToken) Promise<Object>
introspect(token, [tokenTypeHint]) Promise<Object>
introspectMiddleware([config]) Function

Usage

Import the Proxy SDK

const Adaptive = require('adaptive-proxy-sdk');

Initialise an Adaptive object

const config = {
  tenantUrl: 'https://mytenant.ibmcloudsecurity.com',
  clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed',
  clientSecret: '05UXCBaJgL',
};

const adaptive = new Adaptive(config);

Custom transaction storage

You may also pass in a transactionFunctions object to the Adaptive initialisation, as shown below.

const config = {
  tenantUrl: 'https://mytenant.ibmcloudsecurity.com',
  clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed',
  clientSecret: '05UXCBaJgL',
};

const transactionFunctions = {
  createTransaction: myCreateTransactionFunction,
  getTransaction: myGetTransactionFunction,
  updateTransaction: myUpdateTransactionFunction,
  deleteTransaction: myDeleteTransactionFunction
};

const adaptive = new Adaptive(config, transactionFunctions);

This parameter is optional, in case you would like to handle the storing, retrieving, updating, and deleting of transactions created during the A2 flow in an external database. Otherwise, a default in-memory option is used for handling transactions.

If specified, this object must contain four parameters:

  • createTransaction
    • The function used to create (store) a transaction. This function should take one parameter; a transaction Object. It should store the object in a database of choice, indexed by a randomly generated v4 UUID (i.e. the transaction ID). After storing the transaction object associated to a transaction ID, the function should return the transaction ID as a string.
  • getTransaction
    • The function used to retrieve stored transactions. This function should take one parameter; a transaction ID string. It should return the transaction Object associated to the given transaction ID.
  • updateTransaction
    • The function used to update (i.e. add additional properties to) an existing transaction. This function should take two parameters (in order); a transaction ID string of the transaction to update, and an Object of additional properties to add to the transaction. This function shouldn't return anything.
    • For example, if the existing transaction is
      {
        "userId": "123456"
      }
      , and the object passed into this function is
      {
        "name": "John"
      }
      , the updated transaction should result in
      {
        "userId": "123456",
        "name": "John"
      }
  • deleteTransaction
    • The function used to delete an existing transaction. This function should take one parameter; a transaction ID string. The function should remove the transaction associated with the given transaction ID from the database storage. This function shouldn't return anything.

Your storage mechanism of choice should ideally have a time-to-live for the transactions (e.g. 1 hour), to prevent accumulating unused/unfinished transactions.

Assess a policy

Performs the initial grant request to OIDC. This will perform risk assessment on the policy, which will result in either a deny, or requires response.

assessPolicy(context)

Parameter Type Description
context Object See Context Object.

Responses

  • A deny response is received when the policy assessment fails.

    {
      "status": "deny"
    }
  • A requires response will contain an array of allowed factors, indicating that further verification is required (i.e. first-factor verification must be performed) to receive a token. The possible first factor options are "qr", "fido", and "password". You can use the generateQR, generateFIDO, and evaluatePassword functions respectively to initiate these first factors. A transaction ID will also be returned, which will be used to associate subsequent requests to this initial grant.

    {
      "status": "requires",
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "allowedFactors": ["qr", "fido", "password"]
    }

Example Usage

adaptive.assessPolicy(context)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Lookup Identity Sources

Lookup identity sources by name. If name not defined then return all password-capable sources.

lookupIdentitySources(context, transactionId, [sourceName])

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
sourceName string (Optional) name of identity source. e.g. "Cloud Directory".

Response

  • A response containing an array of identity source objects:
     [
       {
         "name": "Cloud Directory",
         "location": "https://<tenant_url>/v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555",
         "id": "11111111-2222-3333-4444-555555555555",
         "type": "ibmldap"
       }
     ]

Example Usage

let identitySourceId
adaptive.lookupIdentitySources(context, transactionId, "Cloud Directory")
    .then((result) => {
      identitySourceId = result[0].id;
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate a password verification

Attempt to complete a password first-factor verification after receiving a requires status from assessPolicy. This will result in either an allow, deny, or requires response.

evaluatePassword(context, transactionId, identitySourceId, username, password)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
identitySourceId string The identifier of the identity source associated with the password registration.
username string The username to authenticate as.
password string The password to authenticate with.

Responses

  • An allow response will contain a token to access the API with.

    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }
  • A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    {
      "status": "deny"
      "detail": {
         "error": "adaptive_more_info_required",
         "error_description": "CSIAQ0298E Adaptive access..."
      }
    }
  • A requires response will contain an array of allowed authentication enrollments, indicating that further verification is required (i.e. second-factor verification must be performed) to receive a token. The possible multi-factor enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". You can use the generateEmailOTP, generateSMSOTP, generateVoiceOTP, evaluateTOTP, generateQuestions, generatePush, and generateFIDO functions respectively to perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be returned.

    {
      "status": "requires",
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "enrolledFactors": [
        {
          "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
          "userId": "60300035KP",
          "type": "emailotp",
          "created": "2020-06-15T02:51:49.131Z",
          "updated": "2020-06-15T03:15:18.896Z",
          "attempted": "2020-07-16T04:30:14.066Z",
          "enabled": true,
          "validated": true,
          "attributes": {
            "emailAddress": "email@email.com"
          }
        }
      ]
    }

Example Usage

adaptive.evaluatePassword(context, transactionId, identitySourceId, username, password)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Generate a FIDO verification

Initiate a FIDO first-factor verification after receiving a requires status from assessPolicy, or a FIDO second-factor verification after receiving a requires status from a first-factor completion (evaluateQR, evaluatePassword, or evaluateFIDO). This will return a FIDO challenge to be sent back to the user for signing.

generateFIDO(context, transactionId, relyingPartyId, userId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
relyingPartyId string The identifier of the relying party associated with the FIDO registration.
userId string The identifier of the OIDC user for which to initiate a FIDO verification.

Response

  • The response will contain a FIDO challenge to be signed by your authenticator, then sent to evaluateFIDO for completion. Your initial transaction ID will also be returned.
    {
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "fido": {
        "rpId": "fido.verify.ibm.com",
        "challenge": "Q29uZ3JhdHVsYXRpb25zIFlvdSBmb3VuZCBpdAo",
        "userVerification": "preferred",
        "timeout": 30000,
        "allowCredentials": [
          {
            "type": "public-key",
            "id": "SSBhbSBhIGNyZWRlbnRpYWwK"
          }
        ]
      }
    }

Example Usage

adaptive.generateFIDO(context, transactionId, relyingPartyId, userId)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate a FIDO verification

Complete a FIDO verification after receiving and signing a FIDO challenge from generateFIDO. This will result in either an allow, deny, or requires response.

evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
relyingPartyId string The identifier of the relying party associated with the FIDO registration.
authenticatorData string The information about the authentication produced by the authenticator.
userHandle string The identifier for the user who owns this authenticator.
signature string The received and signed FIDO challenge from generateFIDO.
clientDataJSON string The base64 encoded client data JSON object.

Responses

  • An allow response will contain a token to access the API with.

    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }
  • A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    {
      "status": "deny"
      "detail": {
         "error": "adaptive_more_info_required",
         "error_description": "CSIAQ0298E Adaptive access..."
      }
    }
  • A requires response can only be received during first factor verification. In that case, the response will contain an array of allowed authentication enrollments, indicating that further verification is required (i.e. second-factor verification must be performed) to receive a token. The possible multi-factor enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". You can use the generateEmailOTP, generateSMSOTP, generateVoiceOTP, evaluateTOTP, generateQuestions, generatePush, and generateFIDO functions respectively to perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be returned.

    {
      "status": "requires",
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "enrolledFactors": [
        {
          "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
          "userId": "60300035KP",
          "type": "emailotp",
          "created": "2020-06-15T02:51:49.131Z",
          "updated": "2020-06-15T03:15:18.896Z",
          "attempted": "2020-07-16T04:30:14.066Z",
          "enabled": true,
          "validated": true,
          "attributes": {
            "emailAddress": "email@email.com"
          }
        }
      ]
    }

Example Usage

adaptive.evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Generate a QR login verification

Initiate a QR login first-factor verification after receiving a requires status from assessPolicy. This will return a QR login code to be sent back to the user for scanning.

generateQR(context, transactionId, profileId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
profileId string The identifier of an IBM Verify registration profile.

Response

  • The response will contain a QR login code to be scanned by your authenticator. Upon scanning, the authenticator should send a request to evaluateQR for completion. Your initial transaction ID will also be returned.
    {
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "qr": {
        "code": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR..."
      }
    }

Example Usage

adaptive.generateQR(context, transactionId, profileId)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate a QR login verification

Complete a QR login first-factor verification after receiving and scanning a QR login code from generateQR. This will result in either a pending, timeout, error, allow, deny, or requires response.

evaluateQR(context, transactionId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.

Responses

  • A pending response indicates the QR code transaction has not yet been completed.

    {
      "status": "pending",
      "expiry": "2021-04-26T12:06:06.501Z"
    }
  • A timeout response indicates the QR code transaction has timed out.

    {
      "status": "timeout",
      "expiry": "2021-04-26T12:06:06.501Z"
    }
  • An error response indicates an error querying the QR code transaction.

    {
      "status": "error"
    }
  • An allow response will contain a token to access the API with.

    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }
  • A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    {
      "status": "deny"
      "detail": {
         "error": "adaptive_more_info_required",
         "error_description": "CSIAQ0298E Adaptive access..."
      }
    }
  • A requires response will contain an array of allowed authentication enrollments, indicating that further verification is required (i.e. second-factor verification must be performed) to receive a token. The possible multi-factor enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". You can use the generateEmailOTP, generateSMSOTP, generateVoiceOTP, evaluateTOTP, generateQuestions, generatePush, and generateFIDO functions respectively to perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be returned.

    {
      "status": "requires",
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "enrolledFactors": [
        {
          "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
          "userId": "60300035KP",
          "type": "emailotp",
          "created": "2020-06-15T02:51:49.131Z",
          "updated": "2020-06-15T03:15:18.896Z",
          "attempted": "2020-07-16T04:30:14.066Z",
          "enabled": true,
          "validated": true,
          "attributes": {
            "emailAddress": "email@email.com"
          }
        }
      ]
    }

Example Usage

adaptive.evaluateQR(context, transactionId)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Generate an email OTP verification

Request an email OTP multi-factor verification after receiving a requires status from a first factor completion (evaluateQR, evaluatePassword, or evaluateFIDO). This will send an OTP to the enroled email address of the user, and return a four-digit correlation associated with the verification. This correlation will be prefixed to the one-time password in the SMS to be sent.

generateEmailOTP(context, transactionId, enrollmentId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in evaluatePolicy.
enrollmentId string The identifier of the email OTP enrollment, received in a requires response after a first-factor attempt.

Example Usage

adaptive.generateEmailOTP(context, transactionId, enrollmentId)
    .then((result) =>{
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Generate an SMS OTP verification

Request an SMS OTP multi-factor verification after receiving a requires status from a first factor completion (evaluateQR, evaluatePassword, or evaluateFIDO). This will send an OTP to the phone number of the user, and return a four-digit correlation associated with the verification. This correlation will be prefixed to the one-time password in the SMS to be sent.

generateSMSOTP(context, transactionId, enrollmentId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assess.
enrollmentId string The identifier of the SMS OTP enrollment, received in a requires response after a first-factor attempt.

Example Usage

adaptive.generateSMSOTP(context, transactionId, enrollmentId)
    .then((result) =>{
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate a TOTP verification

Verify a TOTP second-factor verification after receiving a requires status after a first-factor attempt (evaluateQR, evaluatePassword, or evaluateFIDO). On successful verification, this will result in an allow response.

evaluateTOTP(context, transactionId, enrollmentId, otp)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
enrollmentId string The identifier of the TOTP enrollment, received in a requires response after a first-factor attempt.
otp string The TOTP to verify with.

Responses

  • An allow response will contain a token to access the API with.
    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }

Example Usage

adaptive.evaluateTOTP(context, transactionId, enrollmentId, otp)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate an email OTP verification

Verify an email OTP second-factor verification after receiving an email OTP from generateEmailOTP. On successful verification, this will result in an allow response.

evaluateEmailOTP(context, transactionId, otp)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
otp string The email OTP to verify with. This OTP shouldn't include the correlation prefix (the four digits before the dash).

Responses

  • An allow response will contain a token to access the API with.
    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }

Example Usage

adaptive.evaluateEmailOTP(context, transactionId, otp)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate an SMS OTP verification

Verify an SMS OTP second-factor verification after receiving an SMS OTP from generateSMSOTP. On successful verification, this will result in an allow response.

evaluateSMSOTP(transactionId, otp)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
otp string The SMS OTP to verify with. This OTP shouldn't include the correlation prefix (the four digits before the dash).

Responses

  • An allow response will contain a token to access the API with.
    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }

Example Usage

adaptive.evaluateSMSOTP(context, transactionId, otp)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Generate a knowledge questions verification

Request a knowledge questions second-factor verification after receiving a requires status from a first-factor completion (evaluateQR, evaluatePassword, or evaluateFIDO). This will return a set of the user's knowledge questions to answer.

generateQuestions(context, transactionId, enrollmentId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
enrollmentId string The identifier of the knowledge questions enrollment, received in a requires response after a first-factor attempt.

Response

  • The response will contain a set of knowledge questions to be answered by the user, then sent to evaluateQuestions for completion. Your initial transaction ID will also be returned.
    {
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "questions": [
        {
          "questionKey": "firstHouseStreet",
          "question": "What was the street name of the first house you ever lived in?"
        },
        {
          "questionKey": "bestFriend",
          "question": "What is the first name of your best friend?"
        },
        {
          "questionKey": "mothersMaidenName",
          "question": "What is your mothers maiden name?"
        }
      ]
    }

Example Usage

adaptive.generateQuestions(context, transactionId, enrollmentId)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate a knowledge questions verification

Verify a knowledge questions second-factor verification after receiving and answering a set of knowledge questions from generateQuestions. On successful verification, this will result in an allow response.

evaluateQuestions(context, transactionId, questions)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
questions Object[] The array of objects with a question key (received from generateQuestions) and corresponding answer to verify with.
questions[].questionKey string The identifier of the question received from generateQuestions.
questions[].answer string The answer to the question.

Responses

  • An allow response will contain a token to access the API with.
    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }

Example Usage

adaptive.evaluateQuestions(context, transactionId, questions)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Generate a push notification verification

Request a push notification second-factor verification after receiving a requires status from a first-factor completion (evaluateQR, evaluatePassword, or evaluateFIDO). This will return a correlation code associated with the verification transaction.

generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationTitle, pushNotificationMessage, additionalData)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.
enrollmentId string The identifier of the signature enrollment to perform second-factor verification with.
authenticatorId string The identifier of the authenticator belonging to the signature.
message string The verification message to be displayed in-app.
pushNotificationTitle string The title to be displayed in the push notification banner.
pushNotificationMessage string The message to be displayed in the push notification banner.
additionalData Object[] An array of objects containing "name" and "value" attributes to be displayed in-app.

Example Usage

adaptive.generatePush(context, transactionId, enrollmentId, authenticatorId, message, pushNotificationMessage, pushNotificationMessage, additionalData)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Evaluate a push notification verification

Verify a push notification second-factor verification after receiving a push notification generatePush. On successful verification, this will result in an allow response.

evaluatePush(context, transactionId)

Parameter Type Description
context Object See Context Object.
transactionId string The transaction ID received in assessPolicy.

Responses

  • A pending response indicates the transaction has not yet been completed.

    {
      "status": "pending",
      "expiry": "2021-04-26T12:06:06.501Z",
      "pushState": "SUCCESS"
    }
  • A timeout response indicates the transaction has timed out.

    {
      "status": "timeout",
      "expiry": "2021-04-26T12:06:06.501Z",
      "pushState": "SUCCESS"
    }
  • An error response indicates an error querying transaction.

    {
      "status": "error"
    }
  • An allow response will contain a token to access the API with.

    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }

Example Usage

adaptive.evaluatePush(context, transactionId)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Get Access Token for a transaction

Get the Access Token associated with the in-progress transaction.

getToken(transactionId)

Parameter Type Description
transactionId string The transaction ID received in assessPolicy.

Response

A String is returned containing the Access Token associated with the transaction.

Example Usage

var txnAccessToken = adaptive.getToken(transactionId);

Logout

End the user's session.

logout(accessToken)

Parameter Type Description
accessToken string The access token to revoke, received after a successful second-factor attempt.

Example Usage

adaptive.logout(accessToken)
    .then(() =>{
      res.send(); // Nothing to return
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Refresh

Initiate an OAuth Refresh flow to obtain updated tokens.

refresh(context, refreshToken)

Parameter Type Description
context Object See Context Object.
refreshToken string The refresh token to refresh the access token with.

Responses

  • An allow response will contain a token to access the API with, along with a new refresh token.

    {
      "status": "allow",
      "token": {
        "access_token": "zscmjBdvIjudOPLhpbmJi6nBRJg7cZ6WY0Udw1nC",
        "refresh_token": "wFTjurPxTvRD1cW09itgQM83XwCm1UKwsxhVFb1H7HJh8JkwZz",
        "scope": "openid",
        "grant_id": "a0b440b6-fefb-46ea-a603-e1040534cd28",
        "id_token": "eyJhbGciOiJSUzI1NiIsInR5cC...5j_rMn7H3ZpE4axt0WvsYu4jbA",
        "token_type": "Bearer",
        "expires_in": 7120
      }
    }
  • A deny response is received when the policy denies access or policy evaluation fails. If error information is available, it will be returned in a details attribute.

    {
      "status": "deny"
      "detail": {
         "error": "adaptive_more_info_required",
         "error_description": "CSIAQ0298E Adaptive access..."
      }
    }
  • A requires response will contain an array of allowed authentication enrollments, indicating that further verification is required (i.e. second-factor verification must be performed) to receive a token. The possible multi-factor enrollments are "emailotp", "smsotp", "voiceotp", "totp", "questions", "push" and "fido". You can use the generateEmailOTP, generateSMSOTP, generateVoiceOTP, evaluateTOTP, generateQuestions, generatePush, and generateFIDO functions respectively to perform these 2FA verifications. You can use any of the returned enrollments to perform the second-factor authentication. Your initial transaction ID will also be returned.

    {
      "status": "requires",
      "transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
      "enrolledFactors": [
        {
          "id": "61e39f0a-836b-48fa-b4c9-cface6a3ef5a",
          "userId": "60300035KP",
          "type": "emailotp",
          "created": "2020-06-15T02:51:49.131Z",
          "updated": "2020-06-15T03:15:18.896Z",
          "attempted": "2020-07-16T04:30:14.066Z",
          "enabled": true,
          "validated": true,
          "attributes": {
            "emailAddress": "email@email.com"
          }
        }
      ]
    }

Example Usage

adaptive.refresh(context, refreshToken)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Introspect

Introspect a refresh or access token.

introspect(token, [tokenTypeHint])

Parameter Type Description
token string The refresh or access token to introspect.
tokenTypeHint string The token type. This attribute is an optional hint about the token that is being introspected. Possible values are access_token and refresh_token.

Responses

  • The response will contain an active property which indicates whether the introspected token is valid or invalid. Other properties will also be included when the active status is true.
    {
      "at_hash": "SivVIXwh1lUxzFHqPAMxJQ",
      "ext": {
        "tenantId": "..."
      },
      "sub": "6040004OML",
      "realmName": "cloudIdentityRealm",
      "entitlements" : [
      ...
      ]
      "amr": [
        "emailotp",
        "password"
      ],
      "uniqueSecurityName": "6040004OML",
      "iss": "https://.../oidc/endpoint/default",
      "active": true,
      "preferred_username": "name",
      "token_type": "Bearer",
      "client_id": "57bd5573-73cf-48e5-a42c-656bd2d2ad06",
      "aud": "57bd5573-73cf-48e5-a42c-656bd2d2ad06",
      "acr": "urn:ibm:security:policy:id:331844",
      "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
      "restrictEntitlements": false,
      "scope": "openid",
      "grant_id": "393168ec-eb53-46b8-9957-64158719f075",
      "userType": "regular",
      "category": "application",
      "exp": 1598346175,
      "app_id": "2624486582876118578",
      "iat": 1598338975
    }

Example Usage

adaptive.introspect(token, tokenTypeHint)
    .then((result) => {
      res.send(result);
    }).catch((error) => {
      console.log(error);
      res.status(404).send({error: error.message});
    });

Introspect Middleware

This function returns an Express middleware function, which has a signature of (req, res, next) => (). This middleware will call the introspect function under the hood, and perform additional checks based on the configuration object. If token introspection succeeds, the next middleware will be called in the stack. If an error occurs during token introspection, the error will be passed to the next() function. You may write your custom error handler middleware to catch the error, and handle it accordingly.

A successful introspection result is cached to save on expensive introspection calls for subsequent requests.

introspectMiddleware([config])

Parameter Type Description
config Object The configuration settings used for the token introspection middleware.
config.cacheMaxSize number The maximum size of the cache, i.e. the maximum number of successful token introspection responses to cache. If the cache becomes full, the least-recently-used introspection result will be removed. A value of 0 means no maximum size, i.e. infinity. This value is ignored after first initialisation (i.e. after first call to function). Default value is 0.
config.cacheTTL number The time (in seconds) to cache a successful introspection result for. If a successful token introspection is done, the result will be cached for the period of time provided, to save expensive introspection calls on each subsequent request. A value of 0 will cache the introspect response for the lifetime of the token as provided in the exp property of the introspect response. Default value is 0.
config.denyMFAChallenge boolean A flag indicating whether an introspected token response with a scope of 'mfa_challenge' should be denied. If true, tokens with scope of 'mfa_challenge' will be rejected. If false, the scope of tokens will be disregarded.

Example Usage

// Add the middleware so it's called at every request to a protected endpoint.
// Cache at most 50 successful introspection responses for 15 minutes each.
app.use('/protected', adaptive.introspectMiddleware({cacheMaxSize: 50, cacheTTL: 900, denyMFAChallenge: true}));

// Optionally define a custom error handler, so any errors thrown by previous middleware can be handled.
app.use((err, req, res, next) => {
  console.log(err.message);
  res.sendStatus(403);
});

Demo

A demo Node.js application using the Proxy SDK can be found in the demo folder.

Documentation

Full HTML documentation for the Proxy SDK can be found in the docs folder.

License

MIT License
Copyright 2020 - IBM Corp.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright
notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

About

This library is to provide an interface for device authentication, authorization, and risk assessment using IBM Security Verify.

License:MIT License


Languages

Language:JavaScript 100.0%