Fetch the target account with account_id. Apply and verify the application change, then report success or failed using event_id. A delivery receipt or successful fetch does not mean the application succeeded. Events and reconnect snapshot items include event_id, account_id and account_revision. Verify the account version before applying it. Restart and manual switch commands must first be claimed with running. Make application handlers idempotent; a reconnect may repeat an event.
- Node.js 20.3+ / ws
Install the SDK and use the configuration below. Authorize accounts for pull in Application Management; bind policies only when push or rotation is needed. Obtain the application AK/SK and organization ID from its access materials. Replace placeholders and keep identity material in deployment secrets. Use a stable, unique instance ID for each replica. Fetch by account ID.
export JMS_ENDPOINT='https://jumpserver.example.com'
export JMS_APP_ID='<app-id>'
export JMS_APP_SECRET='<app-secret>'
export JMS_ORG_ID='<org-id>'
export JMS_INSTANCE_ID='app-node-1'
export JMS_ACCOUNT_ID='<account-id>'
Go is distributed with versioned module tags. Java and Node.js are available as SDK source archives in Release 1.0.2; Maven and Node.js are required to install them. Run the following installation commands from your application directory. Add the Java dependency to pom.xml. The examples below use the installed package imports.
curl -fLO https://github.com/jumpserver/pam-clients/releases/download/v1.0.2/jms-pam-node.tar.gz
tar -xzf jms-pam-node.tar.gz
npm install ./nodeconst { Client } = require('@jumpserver/pam')
// ESM: import { Client } from '@jumpserver/pam''use strict'
const { Client } = require('@jumpserver/pam')
async function main() {
const client = new Client({
endpoint: process.env.JMS_ENDPOINT,
appId: process.env.JMS_APP_ID,
appSecret: process.env.JMS_APP_SECRET,
instanceId: process.env.JMS_INSTANCE_ID,
orgId: process.env.JMS_ORG_ID,
})
try {
const account = await client.getAccount({ accountId: process.env.JMS_ACCOUNT_ID })
// Pass account.username / secret to the application connection pool.
console.log(
`Fetched revision ${account.revision}; implement application credential switching.`,
)
} finally {
client.close()
}
}
if (require.main === module)
main().catch((error) => {
console.error(error.code || error.name)
process.exitCode = 1
})Fetch the target account with account_id. Apply and verify the application change, then report success or failed using event_id. A delivery receipt or successful fetch does not mean the application succeeded. Events and reconnect snapshot items include event_id, account_id and account_revision. Verify the account version before applying it. Restart and manual switch commands must first be claimed with running. Make application handlers idempotent; a reconnect may repeat an event.
'use strict'
const { Client } = require('@jumpserver/pam')
async function applyAccount(account) {
// Validate a new connection, switch the pool, then release old connections.
throw new Error('Implement application account switching')
}
async function applyEvent(client, event) {
if (event.event === 'application.restart.requested')
throw new Error('Implement application restart and health check')
const account = await client.getAccount({ accountId: event.accountId, allowLocalFallback: false })
if (account.revision !== event.accountRevision) throw new Error('Event account version is superseded')
await applyAccount(account)
}
async function handleEvent(client, event) {
if (event.commandId) {
const claim = await client.reportApplicationCommandResult({ commandId: event.commandId, status: 'running' })
if (!claim.accepted) return
}
try { await applyEvent(client, event) }
catch (error) {
await client.confirmEvent({ eventId: event.eventId, status: 'failed', errorCode: 'application_failed' })
throw error
}
await client.confirmEvent({ eventId: event.eventId })
}
async function main() {
const client = new Client({ endpoint: process.env.JMS_ENDPOINT, appId: process.env.JMS_APP_ID,
appSecret: process.env.JMS_APP_SECRET, instanceId: process.env.JMS_INSTANCE_ID, orgId: process.env.JMS_ORG_ID })
const stop = () => client.close()
process.once('SIGINT', stop); process.once('SIGTERM', stop)
try {
for await (const event of client.watchCredentialEvents()) {
const updates = event.commandId || event.event === 'credential.updated' ? [event]
: event.event === 'snapshot' ? event.credentials || [] : []
// Reconcile removed connections on snapshots; release revoked accounts.
for (const update of updates) {
try { await handleEvent(client, update) }
catch (error) { console.error(error.code || error.name) }
}
}
} finally { await client.close(); process.off('SIGINT', stop); process.off('SIGTERM', stop) }
}
if (require.main === module) main().catch((error) => { console.error(error.code || error.name); process.exitCode = 1 })get_credential and key-based confirmation remain available for older integrations. New integrations use get_account and confirm_event. The event-result workflow requires the corresponding Core update; SDK 1.0.2 alone cannot add this server capability.
Fetch the target account with account_id. Apply and verify the application change, then report success or failed using event_id. A delivery receipt or successful fetch does not mean the application succeeded. Events and reconnect snapshot items include event_id, account_id and account_revision. Verify the account version before applying it. Restart and manual switch commands must first be claimed with running. Make application handlers idempotent; a reconnect may repeat an event.
getAccount({accountId})getAccount({accountId, allowLocalFallback: false})confirmEvent({eventId, status, errorCode})watchCredentialEvents({signal})watchEvents({signal}) / startEvents({signal}) / stopEvents()EventSubscription.stop() / donelistApplicationCommands()reportApplicationCommandResult({commandId, status, errorCode})executeApplicationCommand(event, handler)syncAgent({credentials, deliveredCredentials, ...})clone() / close()
HTTP, network, authentication and response decoding failures use the SDK exception/error type with code and HTTP status. Close streams and clients when finished. Clones have independent lifecycles. Retry transient failures at the application boundary and never log secrets or authentication headers.
PAMError
All SDKs use protocol version 1; Agent configuration uses schema version 1. A client_upgrade_required response (HTTP 426) requires checking compatibility and upgrading. Unknown optional fields and notification events are tolerated; unsupported policy modes must not be applied or confirmed. Received event receipts are sent automatically and do not prove credential application.
Agent identity uses app_id, app_secret, org_id and a stable instance_id. Application authorization controls pull; policy bindings control push. All file paths and service actions are local: state_file retains the latest passwords, event_file appends metadata without secrets, delivery selects default output, and rules configure files, templates and reload/restart or fixed scripts. On an update notification the Agent fetches the current password, persists it, atomically replaces output files, then runs the configured action. Failed delivery is retried. Use credentials[].key from get_accounts in rules; subscription push keys are account:, independent of the selecting policy. Empty rules write one file per key by default.
Local rules configure target files, JSON/EnvironmentFile rendering or trusted templates, and an optional systemd reload/restart or fixed executable. Scripts receive credential JSON on stdin, use fixed arguments, have a bounded timeout and must validate their application before returning success. Core cannot add script paths or expand local capabilities. Restart the Agent after editing its private configuration.
The downloaded bootstrap contains Agent identity and delivery settings. Edit rules to declare the account IDs used by the business, update its configuration, activate the change and verify the running connection. An account selector with allow_account_switch also follows A/B rotation in either direction. Optional credential_check validates the new login before file changes. The Agent supplies default state, event and socket paths and a 300-second reconciliation interval. Empty rules write one default file per delivered credential.
{
"endpoint": "https://jumpserver.example.com",
"app_id": "<application-id>",
"app_secret": "<application-secret>",
"org_id": "<org-id>",
"instance_id": "orders-node-1",
"delivery": {
"delivery_mode": "json",
"delivery_root": "/opt/jumpserver-pam/credentials",
"app_user": "orders"
},
"rules": []
}rules:
[
{
"accounts": [
{
"account_id": "<primary-account-id>",
"allow_account_switch": true
}
],
"config_update": {
"file": "/etc/order-service/config.yml",
"fields_map": {
"DB_USER": "username",
"DB_PASSWORD": "secret"
}
},
"service_action": {
"unit": "order-service.service",
"operation": "restart"
},
"application_check": {
"path": "/usr/local/libexec/jms-pam/check-running-db",
"confirm_on_success": true
}
}
]jms-pam-agent get_accounts
jms-pam-agent get_secret '<account-id>'
sudo jms-pam-agent check-config
sudo systemctl restart jms-pam-agent