npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ibm-verify/adaptive-proxy

v1.7.0

Published

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

Downloads

5

Readme

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 @ibm-verify/adaptive-proxy

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. | | [evaluationContext="login"] | string | The stage in the user-agent for which to perform an evaluation. (Used for continuous assessment throughout the user-agent.) Different "stages" or "contexts" will result in different evaluation results, as configured in the sub-policies of the tenant application's policy. Possible options are "login" (default), "landing", "profile", "resume", "highassurance", "other". |

Overview

class Adaptive(config, [transactionFunctions])

| 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, credentialId) | ✅ | 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 protected]"
          }
        }
      ]
    }

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. Optional if performing first-factor. |

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, credentialId)

| 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. | | credentialId | string | The Id of the credential (from authenticator). |

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 protected]"
          }
        }
      ]
    }

Example Usage

adaptive.evaluateFIDO(context, transactionId, relyingPartyId, authenticatorData, userHandle, signature, clientDataJSON, credentialId)
    .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 protected]"
          }
        }
      ]
    }

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 protected]"
          }
        }
      ]
    }

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=0] | 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=0] | 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=true] | 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 (c) 2020, 2022 IBM

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.