원클릭으로
a2a-workflow
Use when wiring certificate-based A2A retrieval, brokering, or related Safeguard event listeners in Node.js.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when wiring certificate-based A2A retrieval, brokering, or related Safeguard event listeners in Node.js.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when making Safeguard API calls, wiring auth strategies, or following SDK request and response patterns.
Use when changing module structure, auth internals, conditional exports, or the HTTP and storage layers.
Use when changing tsdown config, Azure Pipelines, publishing flow, or version derivation.
Use when working on Vitest configuration, appliance-backed tests, fixtures, or debugging test failures.
| name | a2a-workflow |
| description | Use when wiring certificate-based A2A retrieval, brokering, or related Safeguard event listeners in Node.js. |
Application-to-Application (A2A) in safeguard.js is the certificate-authenticated, Node-only path for non-interactive secret retrieval and brokering. The main entry point exports A2AClient from src/a2a/index.ts; the browser entry (src/browser.ts) does not. Internally, the client calls Safeguard A2A endpoints under https://{host}/service/a2a/v4/..., sends Authorization: A2A ${apiKey} for credential and broker calls, and returns secrets as SecretValue so callers must opt in to raw material with .expose().
Relevant implementation files are src/a2a/index.ts, src/a2a/types.ts, src/auth/certificate.ts, src/http/node.ts, and samples/node/a2a-password.ts. Across those files, A2AClient supports password retrieval, SSH key retrieval, API key secret retrieval, account discovery, password write-back, private-key write-back, and brokered access requests.
This SDK does not provision A2A registrations or generate API keys. Appliance setup happens first; the SDK starts once you already have a registered certificate and at least one account API key.
On the appliance, create or update the A2A registration that trusts the client certificate your process will present over mTLS. That registration is what authorizes GET /service/a2a/v4/A2ARegistrations and the credential endpoints.
For each retrievable account, generate the A2A API key in Safeguard. In SDK terms that key becomes the apiKey parameter passed to retrievePassword, retrievePrivateKey, retrieveApiKeySecret, setPassword, setPrivateKey, and brokerAccessRequest.
Use the root package entry, not @oneidentity/safeguard/browser:
import { readFileSync } from 'node:fs';
import {
A2AClient,
CertificateAuth,
NodeHttpClient,
} from '@oneidentity/safeguard';
const host = 'safeguard.sample.corp';
const cert = readFileSync('ssl/a2a-cert.pem', 'utf8');
const key = readFileSync('ssl/a2a-cert.key', 'utf8');
const ca = readFileSync('ssl/ca.pem', 'utf8');
const auth = new CertificateAuth({
cert,
key,
passphrase: process.env.SPP_KEY_PASSPHRASE,
});
const a2a = new A2AClient(host, {
auth,
ca,
verify: true,
});
const httpClient = new NodeHttpClient({
...auth.getTlsOptions(),
ca: a2a.ca,
rejectUnauthorized: a2a.verify,
});
a2a.setHttpClient(httpClient);
verify enabled unless you are in a labA2AClientOptions.verify defaults to true. The Node HTTP layer expects rejectUnauthorized, so the common pattern is:
const httpClient = new NodeHttpClient({
...auth.getTlsOptions(),
rejectUnauthorized: a2a.verify,
});
Only use verify: false for development against self-signed appliances.
CertificateAuth accepts cert, key, pfx, certFile, keyFile, and pfxFile options, but A2AClient itself does not load files and does not auto-create a NodeHttpClient. In practice, the safest A2A pattern is to load PEM content yourself, construct CertificateAuth, then inject a preconfigured NodeHttpClient with setHttpClient() before making any A2A call.
getRetrievableAccounts() issues GET https://{host}/service/a2a/v4/A2ARegistrations and returns RetrievableAccount[]:
const accounts = await a2a.getRetrievableAccounts();
for (const account of accounts) {
console.log(account.AssetName, account.AccountName, account.ApiKey);
}
Important fields from src/a2a/types.ts:
AccountIdAssetIdAssetNameAccountNameDomainNameAccountTypeApiKeyUse discovery when you want the appliance to tell you which API keys are valid for the presented certificate.
const password = await a2a.retrievePassword(apiKey);
const rawPassword = password.expose();
Implementation detail: retrievePassword() calls #a2aRequest(apiKey, 'Credentials', 'Password') and wraps the response body in SecretValue.
import { SshKeyFormat } from '@oneidentity/safeguard';
const sshKey = await a2a.retrievePrivateKey(apiKey, SshKeyFormat.OpenSsh);
const rawKey = sshKey.expose();
Available formats from SshKeyFormat:
OpenSshSsh2PuttyInternally the SDK requests GET /service/a2a/v4/Credentials/SshKey?keyFormat=${format}.
const apiSecret = await a2a.retrieveApiKeySecret(apiKey);
const rawSecret = apiSecret.expose();
This maps to GET /service/a2a/v4/Credentials/ApiKey.
Use these only when the appliance registration is allowed to update the managed account:
await a2a.setPassword(apiKey, 'NewPassword123!');
await a2a.setPrivateKey(
apiKey,
privateKeyPem,
optionalPassphrase,
SshKeyFormat.OpenSsh,
);
setPrivateKey() sends a JSON payload with PrivateKey, KeyFormat, and optional Passphrase to PUT /service/a2a/v4/Credentials/SshKey.
A2A brokering is supported through brokerAccessRequest(apiKey, request), which posts to POST /service/a2a/v4/AccessRequests and accepts HTTP 200 or 201.
Relevant enums and types live in src/a2a/types.ts:
BrokeredAccessRequestType.PasswordBrokeredAccessRequestType.SshKeyBrokeredAccessRequestType.ApiKeyBrokeredAccessRequestType.TokenBrokeredAccessRequestType.RdpFileBrokeredAccessRequestType.RemoteDesktopBrokeredAccessRequestType.SshSessionExample:
import {
BrokeredAccessRequestType,
type BrokeredAccessResponse,
} from '@oneidentity/safeguard';
const response: BrokeredAccessResponse = await a2a.brokerAccessRequest(apiKey, {
AccessType: BrokeredAccessRequestType.Password,
AssetId: 123,
AccountId: 456,
ForUserName: 'svc-automation',
});
console.log(response.RequestId);
if (response.AccessToken) {
console.log('Broker token acquired');
}
The response is parsed JSON and always includes RequestId; AccessToken is optional.
There is no A2A-specific SignalR wrapper in this repo. Real-time events are a separate feature exposed from @oneidentity/safeguard/events:
SafeguardEventListener in src/events/listener.tsPersistentSafeguardEventListener in src/events/persistent.tsBoth subscribe to the Safeguard hub method NotifyEventAsync on https://{host}/service/event/signalr.
Use this pattern when an automation process needs both A2A secret retrieval and general Safeguard event monitoring:
A2AClient for A2A retrieval or brokering.PasswordAuth, TokenAuth, or a certificate-based Safeguard login flow.HubConnection with accessTokenFactory.SafeguardEventListener or PersistentSafeguardEventListener.Minimal example:
import { PasswordAuth, NodeHttpClient, MemoryStorage } from '@oneidentity/safeguard';
import { SafeguardEventListener } from '@oneidentity/safeguard/events';
import * as signalR from '@microsoft/signalr';
const auth = new PasswordAuth({ username, password, provider: 'Local' });
const httpClient = new NodeHttpClient();
const storage = new MemoryStorage();
const tokenSet = await auth.authenticate(host, httpClient, storage);
const connection = new signalR.HubConnectionBuilder()
.withUrl(`https://${host}/service/event/signalr`, {
accessTokenFactory: () => tokenSet.accessToken.expose(),
})
.withAutomaticReconnect()
.build();
const listener = new SafeguardEventListener(connection);
listener.on('NotifyEventAsync', (event) => console.log(event.EventName));
await listener.start();
If you need reconnect behavior plus token refresh, use PersistentSafeguardEventListener. It tracks listener state (starting, connected, disconnected, reconnecting, stopped) and refreshes tokens when they are expired or within the built-in 60-second margin.
ConfigurationError: A2AClient requires a hostYou passed an empty host to the constructor. The class validates this immediately in src/a2a/index.ts.
ConfigurationError: A2AClient requires a CertificateAuthA2A in this SDK is certificate-only. Password auth and token auth are not accepted by A2AClientOptions.auth.
ConfigurationError: HttpClient not setEvery A2A call eventually reaches #ensureHttpClient(). Call a2a.setHttpClient(...) before retrievePassword(), getRetrievableAccounts(), or any other A2A method.
Typical causes:
rejectUnauthorized is still true against a self-signed lab applianceStart by validating the NodeHttpClient TLS options and the appliance-side certificate registration.
ApiError on retrieve, write-back, or brokeringA2AClient converts non-success HTTP responses with ApiError.fromResponse(...):
200setPassword() and setPrivateKey() accept 200 or 204brokerAccessRequest() accepts 200 or 201Treat these like appliance or authorization failures and inspect the JSON body for the server message.
[redacted]That is expected. retrievePassword(), retrievePrivateKey(), and retrieveApiKeySecret() return SecretValue, which redacts toString() and toJSON(). Call .expose() only at the point where you truly need the raw secret.
A2A is not exported from src/browser.ts. Use the root package entry in Node.js. If you also need events, install the optional peer dependency first:
npm install @microsoft/signalr
Dispose shared HTTP clients when you shut the process down:
httpClient.dispose?.();
This matches the cleanup pattern used in samples/node/signalr-events.ts and samples/node/persistent-events.ts.