
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
adaptive-proxy-sdk
Advanced tools
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.
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.
Use npm to install the Proxy SDK:
npm install adaptive-proxy-sdk
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.
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". |
class Adaptive(config, [transactionFunctions])const Adaptive = require('adaptive-proxy-sdk');
const config = {
tenantUrl: 'https://mytenant.ibmcloudsecurity.com',
clientId: 'e957e707-c032-4076-98cc-3dcf24db8aed',
clientSecret: '05UXCBaJgL',
};
const adaptive = new Adaptive(config);
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
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
string. It should return the transaction Object associated to the given transaction ID.updateTransaction
string of the transaction to update, and an Object of additional properties to add to the transaction. This function shouldn't return anything.{
"userId": "123456"
}
, and the object passed into this function is
{
"name": "John"
}
, the updated transaction should result in
{
"userId": "123456",
"name": "John"
}
deleteTransaction
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.
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. |
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"]
}
adaptive.assessPolicy(context)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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". |
[
{
"name": "Cloud Directory",
"location": "https://<tenant_url>/v1.0/authnmethods/password/11111111-2222-3333-4444-555555555555",
"id": "11111111-2222-3333-4444-555555555555",
"type": "ibmldap"
}
]
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});
});
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. |
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"
}
}
]
}
adaptive.evaluatePassword(context, transactionId, identitySourceId, username, password)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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"
}
]
}
}
adaptive.generateFIDO(context, transactionId, relyingPartyId, userId)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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"
}
}
]
}
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});
});
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. |
evaluateQR for
completion. Your initial transaction ID will also be returned.
{
"transactionId": "36a101c7-7426-4f45-ab3c-55f8dc075c6e",
"qr": {
"code": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABR..."
}
}
adaptive.generateQR(context, transactionId, profileId)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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"
}
}
]
}
adaptive.evaluateQR(context, transactionId)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
adaptive.generateEmailOTP(context, transactionId, enrollmentId)
.then((result) =>{
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
adaptive.generateSMSOTP(context, transactionId, enrollmentId)
.then((result) =>{
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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
}
}
adaptive.evaluateTOTP(context, transactionId, enrollmentId, otp)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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). |
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
}
}
adaptive.evaluateEmailOTP(context, transactionId, otp)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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). |
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
}
}
adaptive.evaluateSMSOTP(context, transactionId, otp)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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?"
}
]
}
adaptive.generateQuestions(context, transactionId, enrollmentId)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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
}
}
adaptive.evaluateQuestions(context, transactionId, questions)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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});
});
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. |
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
}
}
adaptive.evaluatePush(context, transactionId)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
Get the Access Token associated with the in-progress transaction.
getToken(transactionId)| Parameter | Type | Description |
|---|---|---|
transactionId | string | The transaction ID received in assessPolicy. |
A String is returned containing the Access Token associated with the transaction.
var txnAccessToken = adaptive.getToken(transactionId);
End the user's session.
logout(accessToken)| Parameter | Type | Description |
|---|---|---|
accessToken | string | The access token to revoke, received after a successful second-factor attempt. |
adaptive.logout(accessToken)
.then(() =>{
res.send(); // Nothing to return
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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"
}
}
]
}
adaptive.refresh(context, refreshToken)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
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
}
adaptive.introspect(token, tokenTypeHint)
.then((result) => {
res.send(result);
}).catch((error) => {
console.log(error);
res.status(404).send({error: error.message});
});
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. |
// 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);
});
A demo Node.js application using the Proxy SDK can be found in the demo folder.
Full HTML documentation for the Proxy SDK can be found in the docs folder.
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.
FAQs
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.
We found that adaptive-proxy-sdk demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.