JupiterOne Node.js Client
The @jupiterone/jupiterone-client-nodejs package is a Node.js wrapper for the JupiterOne API. It also installs the j1 command-line tool, which runs J1QL queries and creates, updates, or deletes entities, relationships, alert rules, and questions from JSON or YAML input files.
This is an experimental project and is subject to change. The source code and changelog are on GitHub.
Requirements
- Node.js 22 or later. Version 3.0.0 of the client dropped support for Node.js 18 and 20.
- A JupiterOne API key. See Authentication to create one.
- Your JupiterOne account ID, found in Account Management.
Installation
To install the client in the current project:
npm install @jupiterone/jupiterone-client-nodejs
To install the client and the j1 CLI globally:
npm install -g @jupiterone/jupiterone-client-nodejs
Using the Node.js client
const { JupiterOneClient } = require('@jupiterone/jupiterone-client-nodejs');
async function main() {
const j1Client = await new JupiterOneClient({
account: 'my-account-id',
accessToken: process.env.J1_API_TOKEN,
apiBaseUrl: 'https://api.us.jupiterone.io', // Optional
}).init();
const results = await j1Client.queryV1('FIND jupiterone_account');
const integrationInstance = await j1Client.integrationInstances.get(
'my-integration-instance-id',
);
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
apiBaseUrl defaults to https://api.us.jupiterone.io. Accounts hosted in the EU region use https://api.eu.jupiterone.io.
Beyond queries, the client exposes methods for entities and relationships (createEntity, updateEntity, deleteEntity, createRelationship), alert rules (mutateAlertRule), questions (createQuestion, updateQuestion, deleteQuestion), integration definitions and instances (integrationDefinitions.list, integrationInstances.list, get, create, update, delete), and sync jobs (startSyncJob, uploadGraphObjectsForSyncJob, finalizeSyncJob, abortSyncJob, bulkUpload, bulkDelete).
Query options
queryV1 pages through results with cursors and returns all of them. The second argument accepts Apollo Client query options, which is useful when you need to change how the cache behaves. Inside an async function:
const options = {
fetchPolicy: 'network-only',
};
const results = await j1Client.queryV1('FIND jupiterone_account', options);
See the Apollo Client documentation on fetch policies for the available values.
Using the j1 CLI
$ j1 --help
Usage: j1 [options]
Options:
-v, --version output the version number
-a, --account <name> JupiterOne account name.
-u, --user <email> JupiterOne user email.
-k, --key <apiToken> JupiterOne API access token.
-q, --query <j1ql> Execute a query.
-o, --operation <action> Supported operations:
create,update,upsert,delete,bulk-delete,provision-alert-rule-pack
-e, --entity Specifies entity operations.
-r, --relationship Specifies relationship operations.
-l, --alert Specifies alert rule operations.
-w, --question Specifies question operations. A question is
answered by one or more queries.
-f, --input-file <dir> Input JSON file. Or the filename of the alert rule
pack.
--hard-delete Optionally force hard deletion of entities (default
is soft delete).
--delete-duplicates Optionally force deletion of duplicate entities
with identical keys.
--output-file <file> Writes query result to specified output file, or
results.json by default (default: "results.json")
--api-base-url <url> Optionally specify base URL to use during
execution. (defaults to
`https://api.us.jupiterone.io`)
-h, --help display help for command
Every command needs:
-awith your JupiterOne account ID. The value is sent as theJupiterOne-Accountheader, so use the account ID even though the help text says "account name".- An API key, passed with
-kor set in theJ1_API_TOKENenvironment variable.
The -u (user email) option is a leftover from the old username and password login, which the client no longer supports. Always authenticate with an API key.
Input files can be JSON (.json) or YAML (.yml or .yaml). YAML files are parsed with the YAML 1.2 schema.
Examples
The examples below assume your API key is set in the J1_API_TOKEN environment variable. Otherwise, add -k <api-key> to each command.
Run a J1QL query
$ j1 -a my-account-id -q 'Find jupiterone_account'
Validating inputs... OK
Authenticating with JupiterOne... OK
[
{
"id": "06ab12cd-a402-406c-8582-abcdef001122",
"entity": {
"_beginOn": 1553777431867,
"_createdOn": 1553366320704,
"_deleted": false,
"displayName": "YCO, Inc.",
"_type": [
"jupiterone_account"
],
"_key": "1a2b3c4d-44ce-4a2f-8cd8-99dd88cc77bb",
"_accountId": "my-account-id",
"_source": "api",
"_id": "1a2b3c4d-44ce-4a2f-8cd8-99dd88cc77bb",
"_class": [
"Account"
],
"_version": 6
},
"properties": {
"emailDomain": "yourcompany.com",
"phoneNumber": "877-555-4321",
"webURL": "https://yourcompany.com/",
"name": "YCO"
}
}
]
Done!
Query results are also written to results.json in the current directory. Use --output-file to choose a different file.
Create, update, or delete entities from an input file
$ j1 -a my-account-id -o create --entity -f ./entities.json
Validating inputs... OK
Authenticating with JupiterOne... OK
created 2 entities:
[
"12345678-fe34-44ee-b3b0-abcdef123456",
"12345678-e75f-40d6-858e-123456abcdef"
]
Done!
The operations behave as follows:
createcreates every entity in the file.updateupdates entities identified byentityId, or byentityKeywhen noentityIdis given. Entities whose key is not found, or matches more than one entity, are skipped.upsertworks likeupdate, but creates the entity when its key is not found.deletesoft-deletes entities identified byentityIdorentityKey. Add--hard-deleteto delete them permanently, and--delete-duplicatesto delete every entity that shares the same key.
The input file contains a single entity or an array of entities. For example:
[
{
"entityId": "12345678-fe34-44ee-b3b0-abcdef123456",
"entityKey": "test:entity:1",
"entityType": "generic_resource",
"entityClass": "Resource",
"properties": {
"name": "Test Entity Resource 1",
"displayName": "TER1"
}
},
{
"entityId": "12345678-e75f-40d6-858e-123456abcdef",
"entityKey": "test:entity:3",
"entityType": "generic_resource",
"entityClass": "Resource",
"properties": {
"name": "Test Entity Resource 2",
"displayName": "TER2"
}
}
]
entityId is ignored by create. For the other operations, provide entityId or entityKey.
Create relationships from an input file
j1 -a my-account-id -o create --relationship -f ./relationships.json
Each relationship in the file has relationshipKey, relationshipType, relationshipClass, fromEntityId, toEntityId, and optional properties. The CLI can create relationships but not update them.
Create or update alert rules from an input file
$ j1 -a my-account-id -o create --alert -f ./alerts.json
Validating inputs... OK
Authenticating with JupiterOne... OK
Created 1 alert rules:
[
{
"id": "<uuid>",
"name": "unencrypted-prod-data"
}
].
Done!
The input file contains one alert rule instance or an array of them. The following is an example of a single alert rule instance:
{
"instance": {
"name": "unencrypted-prod-data",
"description": "Data stores in production tagged critical and unencrypted",
"specVersion": 1,
"pollingInterval": "ONE_DAY",
"outputs": ["alertLevel"],
"operations": [
{
"when": {
"type": "FILTER",
"specVersion": 1,
"condition": [
"AND",
["queries.unencryptedCriticalData.total", "!=", 0]
]
},
"actions": [
{
"type": "SET_PROPERTY",
"targetProperty": "alertLevel",
"targetValue": "CRITICAL"
},
{
"type": "CREATE_ALERT"
}
]
}
],
"question": {
"queries": [
{
"query": "Find DataStore with (production=true or tag.Production=true) and classification='critical' and encrypted!=true as d return d.tag.AccountName as Account, d.displayName as UnencryptedDataStores, d._type as Type, d.encrypted as Encrypted",
"version": "v1",
"name": "unencryptedCriticalData"
}
]
}
}
}
To update an alert rule, add "id": "<uuid>" to the instance and use -o update. create skips instances that already have an id.
Create, update, or delete questions from an input file
j1 -a my-account-id -o create --question -f ./questions.json
create creates questions without an id and updates questions that have one. update and delete require an id and skip questions without one.
Bulk delete
j1 -a my-account-id -q 'Find SomeDataClass with someProp="some value" as e return e._id as _id'
j1 -a my-account-id -o bulk-delete --entity -f ./results.json
The first command runs a J1QL query and saves the results to results.json. The second command reads results.json and deletes all of the entities in it through a sync job. Entities that an integration manages are created again on that integration's next run, so bulk delete is best suited to data you uploaded yourself.
Bulk delete reads the _id field at the top level of each object in the input file, so the query must return _id as shown above. The output of a plain Find query nests _id under entity and will not delete anything. Use --relationship instead of --entity to bulk delete relationships, with an input file of objects that each have the relationship's _id.
Provision alert rules from a rule pack
The following command provisions the alert rules in the aws-config rule pack from the jupiterone-alert-rules project:
j1 -a my-account-id -o provision-alert-rule-pack --alert -f aws-config
The CLI looks up rule packs by name in node_modules/@jupiterone/jupiterone-alert-rules/rule-packs/ under the current directory, so run it from a project where the client is installed locally. You can also provision your own rule pack by passing the full path to its JSON file:
j1 -a my-account-id -o provision-alert-rule-pack --alert -f path/to/your/rule-pack.json