@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
Keywords
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
- Configure your IBM Security Verify Tenant.
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 astring
.
- The function used to create (store) a transaction. This function should take one parameter; a transaction
getTransaction
- The function used to retrieve stored transactions. This function should take one parameter; a transaction ID
string
. It should return the transactionObject
associated to the given transaction ID.
- The function used to retrieve stored transactions. This function should take one parameter; a 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 anObject
of additional properties to add to the transaction. This function shouldn't return anything. - For example, if the existing transaction is
, and the object passed into this function is{ "userId": "123456" }
, the updated transaction should result in{ "name": "John" }
{ "userId": "123456", "name": "John" }
- 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
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.
- The function used to delete an existing transaction. This function should take one parameter; a transaction ID
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 thegenerateQR
,generateFIDO
, andevaluatePassword
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 thegenerateEmailOTP
,generateSMSOTP
,generateVoiceOTP
,evaluateTOTP
,generateQuestions
,generatePush
, andgenerateFIDO
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 thegenerateEmailOTP
,generateSMSOTP
,generateVoiceOTP
,evaluateTOTP
,generateQuestions
,generatePush
, andgenerateFIDO
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 thegenerateEmailOTP
,generateSMSOTP
,generateVoiceOTP
,evaluateTOTP
,generateQuestions
,generatePush
, andgenerateFIDO
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 thegenerateEmailOTP
,generateSMSOTP
,generateVoiceOTP
,evaluateTOTP
,generateQuestions
,generatePush
, andgenerateFIDO
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 theactive
status istrue
.{ "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.