
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
identitynow-sdk
Advanced tools
This is a node module for interacting with IdentityNow.
Version 2.0.0 introduced potentially breaking changes, due to some API calls being updated to newly available v3 APIs. Because of this, some of the objects exported may have a different format, and so existing JSON objects you have exported may not import correctly. If this is the case, revert to the latest pre-2.0 version of the library
const idnClient=require('identitynow-sdk');
Authorization needs to be configured during instantiation. The following fields need to be passed in:
| Tenant | Name of the IDN Tenant |
| clientID | Client ID for your API Client or Personal Access Token (PAT) |
| clientSecret | Secret for your API Client or PAT |
| callbackURL | Address your local listener or server will be running on. Only required for interactive user auth |
| userAuthenticate | boolean flag to indicate OAuth user authentication should be performed. (Optional) |
This can be performed in a block like this:
const idnClient=require('identitynow-sdk');
const config={
tenant: 'readme',
clientID: 'b0b15abaddad',
clientSecret: '900dc0ffee',
callbackURL: 'http://localhost:5000/auth/identitynow/callback',
userAuthenticate: true
}
const client=idnClient.Create( config );
ClientID and Secret are generated on the Admin page Global->Security Settings->API Management. a PAT can be generated through REST API calls, or on the 'Preferences' tab of the user menu. Both are outside the scope of this document.
if userAuthenticate is set to true, when a call is made to IdentityNow a browser window will be opened for the user to authenticate. If the user is already authenticated in the browser, then the window will immediately close and execution will continue.
NOTE If you wish to perform API activities that require an ORG_ADMIN connection, you will need to step up in the browser before running your code
ALTERNATIVELY.. If you are using the client from within a server-side Node app, where the app handles the user authentication via browser redirection, you can instantiate the client like so:
const idnClient=require('identitynow-sdk');
const config={
tenant: 'readme',
userToken: <Token passed back to the app via oauth redirect>
userRefreshToken: <Refresh token passed back to the app via oauth redirect>
}
const client=idnClient.Create( config );
All object types support the following options:
tokenize is trueTokenization is the act of replacing specified values in an object with tokens. This process uses JSONPath to identify values that should be replaced. For example, we can replace usernames, passwords and server addresses in a source, that can be replaced with new values when importing into another tenant.
To use, specify tokenize as true in the options of a get call, and then pass an array of tokens as tokens in the options.
For example:
A section of an exported source looks like this:
"description": "AD Access Requests",
"owner": {
"type": "IDENTITY",
"name": "Bob.Bobsson"
},
"cluster": {
"type": "CLUSTER",
"name": "DC1 VA Cluster"
},
.
.
"connectorAttributes": {
.
.
"forestSettings": [
"user": "DC1\Administrator"
.
.
]
}
Passing in a token list like this:
[
{
path: '$.owner.name',
token: 'OWNER'
},
{
path: '$.cluster.name',
token: 'CLUSTER'
},
{
path: '$.connectorAttributes.forestSettings[0].user',
token: 'FOREST_USERNAME'
}
]
Will result in the source looking like this:
"description": "AD Access Requests",
"owner": {
"type": "IDENTITY",
"name": "%%OWNER%%"
},
"cluster": {
"type": "CLUSTER",
"name": "%%CLUSTER%%"
},
.
.
"connectorAttributes": {
.
.
"forestSettings": [
"user": "%%FOREST_USERNAME%%"
.
.
]
}
And also a tokens file that looks like this:
[
{
"token": "%%OWNER%%",
"value": "Bob.Bobsson"
},
{
"token": "%%CLUSTER%%",
"value": "DC1 VA Cluster"
},
{
"token": "%%FOREST_USERNAME%%",
"value": "DC1\Administrator"
}
]
Once you have an authenticated client, the following actions are available
NOTE Unless otherwise specified, all methods will return a Promise
client.AccessProfiles.list( [options] )
client.AccessProfiles.list().then( function ( profiles ) {
....
});
List all access profiles.
Options:
Methods to directly use the V2 or V3 API are available as listv2() and listv3() respectively
client.AccessProfiles.search( query )
client.AccessProfiles.search( 'AD*' ).then( function ( profiles ) {
....
});
Search access profiles. query can contain wildcards
NOTE Uses the V3 API, so to use the results with any wrapped V2 calls translation will be required
client.AccessProfiles.getByName( name [, options])
client.AccessProfiles.getByName( name ).then( function ( profile ) {
....
});
Get an Access Profile by name. This method is designed to return an error if more than one result is found. For multiple results, use AccessProfiles.search()
Options:
client.AccessProfiles.get( id [, options])
client.AccessProfiles.get( id ).then( function ( profile ) {
....
});
Get an Access Profile
Options:
Methods to directly use the V2 or V3 API are available as getv2( id ) and getv3( id ) respectively
client.AccessProfiles.delete( id [, options])
client.AccessProfiles.delete( id ).then( function ( profile ) {
....
});
Delete Access Profile
Options:
Methods to directly use the V2 or V3 API are available as deletev2( id ) and deletev3( id ) respectively
client.AccessProfiles.deleteByName( id [, options])
client.AccessProfiles.deleteByName( id ).then( function ( profile ) {
....
});
Delete Access Profile (by name)
Options:
client.AccessProfiles.create( json [, options])
client.AccessProfiles.create( json ).then( function ( response ) {
....
});
Create an Access Profile
Using names for owner and source is possible; use the attributes ownerName and sourceName instead of ownerId or sourceId to have the SDK perform a lookup into the target system.
entitlements must be specified as IDs (migration to value is a roadmap item)
Options:
Methods to directly use the V2 or V3 API are available as createv2( id ) and createv3( id ) respectively
NOTE There is currently no V3 API for this; trying to use it will return a rejected promise.
client.AccountProfiles.list()
client.AccountProfiles.list().then( function ( profiles ) {
....
});
List all Account profiles.
client.AccountProfiles.get( id )
client.AccountProfiles.get( id ).then( function ( profile ) {
....
});
Get an Account Profile
client.AccountProfiles.update( id, json)
client.AccountProfiles.update( id, json ).then( function ( response ) {
....
});
Update an Account Profile
client.Clusters.list()
client.Clusters.list().then( function ( clusters ) {
....
});
Get a list of VA Clusters
client.Clusters.getByName( name )
client.Clusters.getByName( name ).then( function ( cluster ) {
....
});
Get a specific VA Cluster
client.Entitlements.list( [ options ])
client.Entitlements.list().then( function ( entitlements ) {
....
});
Get a list of entitlements
Options:
client.Entitlements.list( {
sourceName: 'Active Directory',
entitlements: [
'CN=All_Users,OU=Groups,DC=sailpoint,DC=com',
'CN=Corporate-VPN,OU=Groups,DC=sailpoint,DC=com'
]
}).then( function ( entitlements ) {
....
});
client.Identities.list()
client.Identities.list().then( function ( identities ) {
....
});
Get a list of identities
client.Identities.get( id )
client.Identities.get( id ).then( function ( identities ) {
....
});
Get an identity
Options:
getv2( id ) and getv3( id ) respectivelyclient.Roles.list()
client.Roles.list().then( function ( roles ) {
....
});
Get a list of roles
client.Roles.get( id )
client.Roles.get( id, options ).then( function ( role ) {
....
});
Get a role
Available options:
useV3: use V3 APIs (search). Note this will produce output incompatible with V2 APIs
get and importing with create. Currently create relies on CC APIs which use the V2 JSON syntax
dereferenceAccessProfiles: (default: true) whether or not to convert AccessProfile ids to names on output. If so, stored in the accessProfileNames propertyclient.Roles.getByName( roleName)
Same as get but uses role name to get the role
client.Roles.create( json )
client.Roles.create( json ).then( function ( role ) {
console.log( 'created role' );
console.log( JSON.stringify( role, null, 2 ) );
})
Create a role. Uses a JSON object in the format returned by get or getByName. Access Profile names in the accessProfileNames property will be translated to IDs in accessProfileIds as required by the underlying API.
client.Sources.list()
client.Sources.List().then( function ( sources ) {
....
});
Get a list of sources
client.Sources.get( id [, options] )
Get a specific source by ID.
client.Sources.get( 'abcdef1234' ).then( function ( source ) {
....
});
Get a 'clean' version of the source. Strips out all IDs as they will only be accurate in the tenant the source is extracted from
client.Sources.get( 'abcdef1234', { clean: true } ).then( function ( source) {
....
});
Get an 'exported' version of the source. This will collect sub-objects (such as Schemas) and bundle them in the response.
client.Sources.get( 'abcdef1234', { clean: true, export: true } ).then( function ( object ) {
....
});
This will return something like:
source: { <source data> },
schemas: [
{ <schema data> },
{ <schema data> }
]
...
connectorFiles: {
<filename>:
}
}
Options:
Get a specific source by ID.
client.Sources.getByName( name [, options] )
client.Sources.getByName( 'Active Direectory' ).then( function ( source) {
....
});
The same options as get( id ) are available
Alternative call to get a zip of a specific source with its associated objects
client.Sources.getZip( 'abcdef1234' ).then( function ( zip ) {
....
});
This returns a zip object (using the JSZip library) which can then be written to a file. For example:
client.Sources.getZip( 'abcdef1234' ).then( function (zip) {
zip
.generateNodeStream({type:'nodebuffer',streamFiles:true})
.pipe(fs.createWriteStream('out.zip'))
.on('finish', function () {
// JSZip generates a readable stream with a "end" event,
// but is piped here in a writable stream which emits a "finish" event.
console.log("out.zip written.");
});
})
Create a new source
client.Sources.create( object );
When creating a source, the object passed in can contain all the sub-objects (schemas etc.) associated with the source. At a minimum, it must contain a definition of the source:
{
source: {
description: 'My Source',
...
}
}
It can also contain Schemas (this list continues to be extended)
Owner and Cluster can be specified by name; the SDK will look up the relevant ID in the IDN tenant
TODO
var source=client.Sources.delete( 'abcdef1234' )
var sources = client.Schemas.List();
Get a specific source by ID
var source = client.Schemas.get( 'abcd1234' );
client.Schemas.create( 'abcdef1234', object );
Create a schema. Pass in the ID of the Source, and the object representing the schema
TODO
client.Schemas.delete( 'abcdef1234', 'badc0ffee' ).then( function( ok ){
....
})
Delete a schema. Pass in the ID of the Source, and the ID of the schema
client.Transforms.List().then( function( items ){
....
});
Return value looks like:
[
{
"attributes": null,
"id": "ToUpper",
"type": "upper"
},
{
"attributes": null,
"id": "ISO3166 Country Format",
"type": "iso3166"
},
....
]
Get a specific transform by ID
client.Schemas.get( 'ToUpper' ).then( function (transform) {
....
});
TODO
TODO
TODO
client.AccountProfiles.list( 'abcdef1234' ).then( function( profiles ) {
....
});
Returns a list of account profiles for the specified source. Returns an Array
client.AccountProfiles.get( 'abcdef1234', 'Create' ).then( function( profile ) {
....
});
Returns the account profile for the specified source and Usage
client.VirtualAppliances.createCluster( { clusterName: 'My Cluster'} ).then( function( cluster ) {
....
});
Creates a new VA cluster. Returns the new cluster object in JSON format
client.VirtualAppliances.createVA( { clusterid: <CC cluster ID>} ).then( function( vaConfig ) {
....
});
Creates a new VA in the specified cluster. Returns:
{
id: <VA ID>,
yamlSource: <VA YAML config file as a string>,
yamlObject: <VA config as a JSON object>
}
FAQs
SDK for IdentityNow
We found that identitynow-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
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.