@volcengine/agent-identity 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,388 @@
1
+ # Agent Identity Plugin
2
+
3
+ UserPool OIDC login, TIP (Trusted Identity Provider) token via Identity GetWorkloadAccessTokenForJWT, credential 3LO (GetResourceOauth2Token/Oauth2Callback), and session management for OpenClaw.
4
+
5
+ > 中文文档请参阅 [README-cn.md](README-cn.md)
6
+
7
+ Integrates with [Volcengine Agent Identity and Permission Management](https://www.volcengine.com/docs/86848).
8
+
9
+ ## Features
10
+
11
+ - **OIDC Login**: `/identity login` returns IdP auth URL (no HTTP start endpoint). User opens URL, IdP redirects to `/identity/oauth/callback`.
12
+ - **Pre-LLM Auth Gate (`before_dispatch`)**: Blocks unauthenticated messages before the LLM is invoked, saving tokens. Returns an OIDC login URL directly in the static response. Falls back to `before_agent_start` on older OpenClaw versions.
13
+ - **TIP Token**: `before_dispatch` / `before_agent_start` hooks fetch TIP token when session has a logged-in user.
14
+ - **Credential 3LO**: `/identity fetch <provider>` returns auth URL. IdP redirects to Identity-provided callback (control-plane config).
15
+ - **Credential Binding**: `/identity set <provider> <envVar>` binds stored credential to env var. Credentials are securely injected per-tool-call, isolated between concurrent multi-user sessions.
16
+ - **Local Identity Server (UDS)**: Optional HTTP-over-Unix-Domain-Socket server exposing TIP tokens, OIDC session tokens, and all plugin tools to other local processes. Supports peer credential checking (Linux `SO_PEERCRED` + `/proc`) and configurable process allowlist.
17
+ - **Encrypted Session Storage**: `sessions.json` is encrypted at rest (AES-256-GCM). Plaintext sessions from older versions are auto-migrated on first load.
18
+ - **In-memory TIP Cache**: TIP tokens are stored only in memory (no disk persistence). They are short-lived and re-obtained from the user's session token on demand.
19
+ - **Dynamic UserPool**: Resolve OIDC config by `userPoolName` + `clientName` (no manual clientId).
20
+ - **Credentials**: Load AK/SK from env, file, or STS AssumeRole (veadk-style).
21
+
22
+ ## HTTP Endpoints
23
+
24
+ Only the OIDC login callback is exposed. Credential OAuth uses Identity callback. All other logic runs in slash commands.
25
+
26
+ | Path | Method | Description |
27
+ | -------------------------- | ------ | ---------------------------------------- |
28
+ | `/identity/oauth/callback` | GET | OIDC login callback (IdP redirects here) |
29
+
30
+ ## Slash Commands
31
+
32
+ Single command `/identity` (alias `/id`) with subcommands. Default with no args: `status`.
33
+
34
+ | Subcommand | Description |
35
+ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------- |
36
+ | _(none)_ | Show help. |
37
+ | `whoami` | Show current session identity (sub, TIP status). |
38
+ | `login` | If logged in: refresh TIP. If not: return OIDC IdP URL to open. |
39
+ | `status` | Show login status, TIP, credentials. Tries to refresh TIP when session exists. |
40
+ | `logout` | Clear session and TIP for current session. |
41
+ | `list-tips` | List all valid TIP tokens with delegation chain, expiry, and env bindings. |
42
+ | `config` | Show identity plugin config (sensitive values redacted). |
43
+ | `list-credentials` or `list [page]` | List providers from control plane (paginated) and your credentials with bound env. Use `list 2` to load more. |
44
+ | `list-roles` | List STS role credential providers (not OAuth/API key). Optional name prefix filter. |
45
+ | `get-role <provider> [--use-tip] [--show-secrets]` | Get temporary STS credentials for a role provider (masked by default). |
46
+ | `fetch <provider> [--flow=...]` | Add credential. Flow auto-inferred from provider type (api_key/oauth2/m2m); override with `--flow`. |
47
+ | `set <provider> <envVar>` | Bind credential to env var for tool injection. If no credential, import from `process.env[envVar]`. |
48
+ | `unset <provider>` | Remove env binding for provider. |
49
+
50
+ ## OIDC Login Flow
51
+
52
+ 1. User sends `/identity login` in chat (e.g. Telegram, Discord)
53
+ 2. Command derives sessionKey from channel/sender, builds IdP authorize URL, stores state
54
+ 3. Command returns the IdP URL; user opens it in browser
55
+ 4. User completes login at UserPool IdP
56
+ 5. IdP redirects to `/identity/oauth/callback` with `code` and `state`
57
+ 6. Plugin exchanges code, creates session, shows success page and sends message to chat
58
+
59
+ ## Credential Fetch Flow
60
+
61
+ **OAuth2 (user federation or M2M):**
62
+
63
+ 1. User sends `/identity fetch google` or `/identity fetch google --flow=oauth2-m2m` (after `/identity login`)
64
+ 2. Command uses TIP to call Identity API; returns auth URL or direct token
65
+ 3. If auth URL: user opens it; IdP redirects to Identity callback (control-plane provider config)
66
+ 4. Identity handles callback; token obtained via Identity; user may re-run fetch to pull credential
67
+
68
+ **API Key:**
69
+
70
+ 1. User sends `/identity fetch openai` (provider type api_key in control plane) or `/identity fetch openai --flow=apikey`
71
+ 2. Command uses TIP to call GetResourceApiKey; API key stored directly
72
+
73
+ Flow is auto-inferred from ListCredentialProviders (Type + Flow). Override with `--flow=oauth2-user|oauth2-m2m|apikey` when needed.
74
+
75
+ ## Enable Volcengine Agent Identity Service
76
+
77
+ Before using this plugin, you must enable **Agent Identity and Permission Management** in Volcengine and complete authorization. See:
78
+
79
+ - [Enable Agent Identity Service (Chinese)](https://www.volcengine.com/docs/86848/2123358?lang=zh)
80
+
81
+ ## Get Volcengine AK/SK
82
+
83
+ The plugin requires Volcengine Access Key and Secret Key to call the Identity API. To create credentials:
84
+
85
+ - [Create Access Key - Volcengine Docs](https://www.volcengine.com/docs/6291/65568?lang=zh)
86
+
87
+ After creating AK/SK in the console, pass them via config or use environment variables `VOLCENGINE_ACCESS_KEY` and `VOLCENGINE_SECRET_KEY`.
88
+
89
+ ## Installation
90
+
91
+ ```bash
92
+ openclaw plugins install @m1a0rz/agent-identity
93
+ ```
94
+
95
+ Or with link for development:
96
+
97
+ ```bash
98
+ openclaw plugins install --link .
99
+ ```
100
+
101
+ ## Configuration
102
+
103
+ ### Step 2: Configure plugin (minimal setup)
104
+
105
+ The plugin typically needs three types of config:
106
+
107
+ **A. Platform access (Identity)**: For TIP Token, credential fetch/hosting, and optional permission checks.
108
+
109
+ - `endpoint` (optional): Full Identity API base URL (e.g. `https://id.cn-beijing.volcengineapi.com`). **Highest priority** for the API host.
110
+ - `regionMetadataUrl` (optional): HTTP(S) URL that returns a **plain-text region id** (e.g. `cn-beijing`). Used only when `endpoint` is **unset**: the client builds `https://id.{region}.volcengineapi.com`. Request timeout ~10s; on failure or invalid body (e.g. `unknown`), falls back to `https://id.cn-beijing.volcengineapi.com`. Example metadata URL: `http://100.96.0.96/latest/region_id` (must be reachable from the gateway).
111
+ - `accessKeyId` / `secretAccessKey`: For Identity API access. **Optional** when using env vars or credential file (see below).
112
+ - `workloadPoolName` / `workloadName`: For issuing TIP Token. Defaults: `default`, `openclaw-agent`.
113
+ - `audience` / `durationSeconds`: Optional, token audience and validity.
114
+ - `credentialsFile`: Path to credential JSON. Default: `VOLCENGINE_CREDENTIALS_FILE` env or `/var/run/secrets/iam/credential`.
115
+ - `credentialsMetadataUrl`: Full URL for remote credential fetch. When set with `roleTrn`, fetches from URL (response: `AccessKeyId`, `SecretAccessKey`, `SessionToken`), then AssumeRole with `roleTrn` to get final credentials. Same flow as AK/SK + roleTrn. 404 falls through to credential file. Cached by ExpiredTime. Must be explicitly configured.
116
+ - `roleTrn`: Role TRN for STS AssumeRole. When set (and `workloadName` not set), workload name is omitted; backend uses roleName. Priority: `workloadName` > `roleTrn` > params. Used with `credentialsMetadataUrl` (AssumeRole after fetch) or explicit AK/SK.
117
+ - `sessionToken`: STS session token (or use `VOLCENGINE_SESSION_TOKEN` env).
118
+
119
+ **Identity API host resolution**: `endpoint` if set → else region from `regionMetadataUrl` → else `https://id.cn-beijing.volcengineapi.com`. **SigV4 signing region** is inferred from the resolved host when it matches `id.{region}.volcengineapi.com`; otherwise `cn-beijing`.
120
+
121
+ **Workload pool (credentials / STS)**: `workloadPoolName` (default `default`) scopes `ListCredentialProviders`, `ListRoleCredentialProviders`, and control-plane calls such as `GetResourceOauth2Token`, `GetResourceApiKey`, `GetUserCredential`, and `GetRoleCredentials` via `PoolName`. Role provider listing also filters by `userpool.userPoolName` when configured.
122
+
123
+ **Credential resolution order** (AK/SK): 1) Explicit config → 2) Env vars (`VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`, `VOLCENGINE_SESSION_TOKEN`) → 3) Remote metadata (`credentialsMetadataUrl` + `roleTrn`, fetches from full URL then AssumeRole; 404 falls through) → 4) Credential file (`credentialsFile` config, or `VOLCENGINE_CREDENTIALS_FILE` env, or `/var/run/secrets/iam/credential`). Credential file format (VeFaaS): `access_key_id`, `secret_access_key`, `session_token` (optional), `role_trn` (optional for AssumeRole). `RUNTIME_IAM_ROLE_TRN` env can supply role TRN when loading from file.
124
+
125
+ **B. User login (UserPool / OIDC)**: For `/identity login` and session setup.
126
+
127
+ - `discoveryUrl` (or `userPoolName` + `clientName` for dynamic resolution)
128
+ - `clientId` / `clientSecret` (auto-resolved in dynamic mode)
129
+ - `callbackUrl`: Public callback URL for OpenClaw gateway, e.g. `http://127.0.0.1:18789/identity/oauth/callback`
130
+ - `scope`: Typically `openid profile email`
131
+ - `identityProvider` (optional): IdP name for the `identity_provider` authorize param. When omitted, the first entry from `ListIdentityProviders` is used.
132
+ - `useRelayCallback` (optional): UserPool relay / `redirect_relay_uri` flow for OIDC callback. Default false.
133
+
134
+ **C. AuthZ and risk approval (optional)**: For TIP + CheckPermission + risk evaluation. Each flag is independent; no single "enable" switch.
135
+
136
+ - `agentCheck`: Run CheckPermission for agents (resource type agent) in `before_agent_start`. Verifies the user can invoke the current agent. Uses the outermost actor from TIP delegation chain as resource id. Default false.
137
+ - `toolCheck`: Run CheckPermission for tools (resource type tool). Default false.
138
+ - `skillReadCheck`: Run CheckPermission for read of SKILL.md (resource type skill). Parses available_skills from system prompt. Default false.
139
+ - `requireRiskApproval`: Require user approval for high-risk tool calls. Default false.
140
+ - `namespaceName`: CheckPermission Cedar policy namespace. Default `default`.
141
+ - `lowRiskBypass`: Skip TIP+CheckPermission for built-in low-risk tools. Default true.
142
+ - `lowRiskTools`: Extra tool names treated as low-risk.
143
+ - `enableLlmRiskCheck`: Use LLM to re-evaluate when rules return medium. Default false.
144
+ - `llmRiskCheck`: LLM config (`endpoint`, `api`, `model`, `apiKey`, `timeoutMs`, `cacheTtlMs`). Required when `enableLlmRiskCheck` is true.
145
+ - `approvalTtlSeconds`: Approval link/command TTL (seconds). Default 300.
146
+
147
+ **Expected outcome**: After config, the plugin can initiate login and obtain TIP Token. With AuthZ flags enabled, agent/tool/skill permission checks and high-risk approvals apply. High-risk tool calls use OpenClaw's native `requireApproval` mechanism (UI overlay, Telegram buttons, Discord interactions, `/approve` CLI).
148
+
149
+ ---
150
+
151
+ Add to `openclaw.json` under `plugins.entries.agent-identity.config`:
152
+
153
+ ```json
154
+ {
155
+ "plugins": {
156
+ "entries": {
157
+ "agent-identity": {
158
+ "config": {
159
+ "identity": {
160
+ "endpoint": "https://id.cn-beijing.volcengineapi.com",
161
+ "workloadPoolName": "default",
162
+ "workloadName": "openclaw-agent"
163
+ },
164
+ "userpool": {
165
+ "discoveryUrl": "https://userpool-xxx.userpool.auth.id.cn-beijing.volces.com",
166
+ "clientId": "<client-id>",
167
+ "clientSecret": "<client-secret>",
168
+ "callbackUrl": "https://gateway.example.com/identity/oauth/callback",
169
+ "scope": "openid profile email"
170
+ },
171
+ "authz": {
172
+ "agentCheck": false,
173
+ "toolCheck": false,
174
+ "skillReadCheck": false,
175
+ "requireRiskApproval": false,
176
+ "namespaceName": "default",
177
+ "lowRiskBypass": true,
178
+ "enableLlmRiskCheck": false,
179
+ "approvalTtlSeconds": 300
180
+ },
181
+ "localServer": false,
182
+ "localServerAllowlist": [],
183
+ "localServerFailOpen": true
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ **Identity credentials**: Omit `accessKeyId`/`secretAccessKey` to use env vars (`VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`) or credential file (`VOLCENGINE_CREDENTIALS_FILE` or `/var/run/secrets/iam/credential`).
192
+
193
+ ### identity config (required vs optional)
194
+
195
+ | Param | Type | Required | Description |
196
+ |-------|------|----------|--------------|
197
+ | `endpoint` | string | No | Identity API base URL. Omit to use `regionMetadataUrl` or default `https://id.cn-beijing.volcengineapi.com` |
198
+ | `regionMetadataUrl` | string | No | Plain-text region id URL; builds `https://id.{region}.volcengineapi.com` when `endpoint` unset |
199
+ | `accessKeyId` | string | No* | Volcengine Access Key. Omit to load from `VOLCENGINE_ACCESS_KEY` or `credentialsFile` |
200
+ | `secretAccessKey` | string | No* | Volcengine Secret Key. Omit to load from `VOLCENGINE_SECRET_KEY` or `credentialsFile` |
201
+ | `workloadPoolName` | string | No | Workload pool name, default `default` |
202
+ | `workloadName` | string | No | Workload name for TIP. When set, takes precedence over roleTrn. Default when neither set: agentId or `openclaw-agent` |
203
+ | `audience` | string[] | No | TIP token audience |
204
+ | `durationSeconds` | number | No | TIP token TTL (seconds), default 3600 |
205
+ | `roleTrn` | string | No | Role TRN for STS AssumeRole. When set (and workloadName not set), workload name is omitted; backend uses roleName. Priority: workloadName > roleTrn > params |
206
+ | `credentialsFile` | string | No | Path to credential JSON. Default: `VOLCENGINE_CREDENTIALS_FILE` or `/var/run/secrets/iam/credential` |
207
+ | `credentialsMetadataUrl` | string | No | Full URL for remote credential fetch. When set with `roleTrn`, fetches then AssumeRole. 404 falls through to `credentialsFile` |
208
+ | `sessionToken` | string | No | STS session token (or `VOLCENGINE_SESSION_TOKEN`) |
209
+ | `subagentTipPropagation` | boolean | No | Propagate TIP and session to subagents. Default false |
210
+ | `webchatSessionExchange` | boolean | No | Enable `identity.session.put` / `identity.session.get` gateway WS methods for webchat clients. Default false |
211
+ | `personalSessionMode` | boolean | No | Single-user mode: TIP, OIDC session, and credentials are stored only under `agent:main:main` (no per-sender or per-channel-peer keys). Subagent sessions unchanged. Default false — do not enable for multi-tenant or shared groups. |
212
+ | `localServer` | boolean | No | Enable the local UDS identity server. Default false. See [Local Identity Server (UDS)](#local-identity-server-uds). |
213
+ | `localServerAllowlist` | string[] | No | Additional process names/paths allowed to access the UDS server. `curl` always allowed. |
214
+ | `localServerFailOpen` | boolean | No | Allow connections when peer cannot be identified. Default true. |
215
+
216
+ \* AK/SK must be provided via `accessKeyId`+`secretAccessKey`, environment variables, `credentialsMetadataUrl`+`roleTrn`, or `credentialsFile`.
217
+
218
+ **Environment variables**: `VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`, `VOLCENGINE_SESSION_TOKEN`, `VOLCENGINE_CREDENTIALS_FILE`, `RUNTIME_IAM_ROLE_TRN` (for AssumeRole when loading from file). Set `IDENTITY_STS_DEBUG=1` to log full STS AssumeRole request/response for debugging.
219
+
220
+ ### userpool config (OIDC login)
221
+
222
+ **Explicit mode** (required): `discoveryUrl`, `clientId`, `clientSecret`, `callbackUrl`, `scope`
223
+
224
+ **Dynamic mode** (required): `userPoolName`, `clientName`, `callbackUrl`; `autoCreate` defaults to true
225
+
226
+ OAuth2 credential fetch uses control-plane redirect URL and scopes. Override via `/identity fetch <provider> --redirectUrl` and `--scopes`.
227
+
228
+ ### authz config (optional, each flag independent)
229
+
230
+ | Param | Type | Description |
231
+ |-------|------|-------------|
232
+ | `agentCheck` | boolean | Run CheckPermission for agents (resource type agent) in `before_agent_start`. Verifies the user can invoke the current agent. Uses the outermost actor from TIP delegation chain as resource id. Default false. |
233
+ | `toolCheck` | boolean | Run CheckPermission for tools (resource type tool). Default false. |
234
+ | `skillReadCheck` | boolean | Run CheckPermission for read of SKILL.md (resource type skill). Default false. |
235
+ | `requireRiskApproval` | boolean | Require user approval for high-risk tools. Default false. |
236
+ | `namespaceName` | string | CheckPermission Cedar namespace. Default `default`. |
237
+ | `lowRiskBypass` | boolean | Skip TIP+CheckPermission for built-in low-risk tools. Default true. |
238
+ | `lowRiskTools` | string[] | Extra tool names treated as low-risk. |
239
+ | `enableLlmRiskCheck` | boolean | Re-evaluate with LLM when rules return medium. Default false. |
240
+ | `llmRiskCheck` | object | LLM config: `endpoint`, `api`, `model`, etc. Required when `enableLlmRiskCheck` is true. |
241
+ | `approvalTtlSeconds` | number | Approval TTL (seconds). Default 300. |
242
+
243
+ ### Workload and TIP
244
+
245
+ TIP token is obtained via `GetWorkloadAccessTokenForJWT`. Workload behavior:
246
+
247
+ - **workloadName** (optional): Workload name sent to the API. Priority: config.workloadName > config.roleTrn > params (session agentId or `"openclaw-agent"`). When config.workloadName is set, it takes precedence over roleTrn.
248
+ - **roleTrn** (optional): When set (and workloadName not set), the plugin does **not** pass workload name; the backend uses the role name. Use this for delegated execution (e.g. VeFaaS, K8s IRSA).
249
+ - **Auto-create workload**: When `GetWorkloadAccessTokenForJWT` returns 404 (workload not found), the plugin calls `CreateWorkloadIdentity` to create the workload (Category: Agent), then retries. Only applies when a workload name is used (workloadName set or neither workloadName nor roleTrn set). Duplicated (409) from concurrent create is ignored.
250
+
251
+ ### Feishu notifications
252
+
253
+ Login success and credential fetch follow-up messages (e.g. "✓ Credential for `google` added.") are sent via Feishu when the user runs `/identity` from a Feishu chat. Credentials are read from `channels.feishu` in openclaw.json (same as feishu extension: `appId`, `appSecret`, optional `accounts`). No extra config in agent-identity is required.
254
+
255
+ **Approval messages** (when a high-risk tool is blocked): The plugin returns `requireApproval` from `before_tool_call`, and OpenClaw handles the approval UI natively across all channels (exec overlay, Telegram buttons, Discord interactions, `/approve` CLI). No plugin-side delivery logic is needed.
256
+
257
+ ### WebChat Session Exchange (Gateway WS Methods)
258
+
259
+ When `identity.webchatSessionExchange` is `true`, the plugin registers two gateway WebSocket methods for webchat clients to inject and retrieve session tokens without going through the OIDC redirect flow:
260
+
261
+ | Method | Params | Response | Description |
262
+ | --- | --- | --- | --- |
263
+ | `identity.session.put` | `{ sessionKey, idToken, refreshToken?, senderId?, channel? }` | `{ sub, expiresAt, effectiveSessionKey, hasTip }` | Inject an OIDC id_token into a plugin session; optional `refreshToken` is stored encrypted for silent token renewal. Resolves effective storage key via `buildEffectiveSessionKey` (same sender isolation as hooks/commands). |
264
+ | `identity.session.get` | `{ sessionKey, senderId?, channel? }` | `{ userToken, sub, expiresAt, effectiveSessionKey, hasRefreshToken }` | Retrieve the stored user token for a session. `hasRefreshToken` indicates whether a refresh token is stored; the refresh token value is never returned. |
265
+
266
+ - `senderId` defaults to `"openclaw-control-ui"`. The effective storage key is `agent:main:main:user:<senderId>` for main sessions.
267
+ - `channel` is optional; when the session originates from a sendable channel (feishu, telegram, etc.), pass it to enable per-channel-peer key promotion.
268
+
269
+ Both methods are **restricted to webchat WS connections only** (`isWebchatConnect` check). Non-webchat clients receive a `FORBIDDEN` error.
270
+
271
+ **Config:**
272
+
273
+ ```json
274
+ {
275
+ "identity": {
276
+ "webchatSessionExchange": true
277
+ }
278
+ }
279
+ ```
280
+
281
+ **Typical flow (BFF → webchat → plugin):**
282
+
283
+ 1. BFF completes 3LO login and obtains an OIDC `id_token` for the user
284
+ 2. Webchat client calls `identity.session.put` with the session key and `id_token` (optionally `refreshToken` from the token response if silent renewal is desired)
285
+ 3. Plugin verifies the token, stores the session, and acquires TIP
286
+ 4. Subsequent agent runs in that session have a valid identity — no manual login needed
287
+
288
+ ### WebChat / TUI
289
+
290
+ Follow-up messages (login success, credential fetch done) are not delivered when the user runs `/identity` from WebChat or TUI; the plugin has no API to push to those channels. Use `/identity status` to confirm results.
291
+
292
+ ## Tools
293
+
294
+ Agent-facing behavior is summarized in [`skills/SKILL.md`](skills/SKILL.md). Registered tools:
295
+
296
+ - **identity_whoami** — Session identity (sub, TIP)
297
+ - **identity_status** — Login, TIP, credentials, bindings
298
+ - **identity_login** / **identity_logout** — OIDC login or refresh TIP; clear session
299
+ - **identity_list_credentials** — OAuth/API key providers and stored credentials (`page`, `name`, `flow`, `type` filters)
300
+ - **identity_list_roles** — STS role credential providers (`name` prefix filter)
301
+ - **identity_fetch** — Add credential (`provider`, `flow`, `redirectUrl`, `scopes`, `returnValue`)
302
+ - **identity_get_role_credentials** — STS credentials for a role provider (`providerName`, `useTip`)
303
+ - **identity_get_tip_token** / **identity_get_session_token** — Raw TIP JWT or session user token (advanced)
304
+ - **identity_config** — Effective plugin config (redacted)
305
+ - **identity_config_suggest** — Config merge snippets (`intent`, `lang`)
306
+ - **identity_set_binding** / **identity_unset_binding** — Env var bindings for tool injection
307
+ - **identity_risk_check** / **identity_list_risk_patterns** — Risk evaluation (optional plugin)
308
+ - **identity_list_tips** — All valid TIP tokens and bindings (ops / multi-session debug)
309
+
310
+ ## Hooks
311
+
312
+ - **before_dispatch** - Stateless pre-LLM authentication gate. Checks for a valid TIP token before the LLM is invoked. If no TIP is found, blocks the message with a static response containing an OIDC login URL. Zero LLM token cost for unauthenticated users. When `authz.agentCheck` is enabled, also runs agent-level CheckPermission. Sets a feature flag so `before_agent_start` skips redundant auth logic.
313
+ - **before_agent_start** - Fallback auth gate for older OpenClaw versions that do not support `before_dispatch`. When `before_dispatch` is active, this hook is a no-op for authentication. Still fetches TIP token and runs agent CheckPermission when applicable.
314
+ - **subagent_spawned** - Propagate TIP to child session on subagent spawn.
315
+ - **before_tool_call** - Group context injection, optional AuthZ (TIP check, CheckPermission, risk via `requireApproval`), and per-tool-call credential injection. High-risk tool calls return `requireApproval` to the OpenClaw framework, which handles approval UI natively.
316
+ - **after_tool_call** - Clean up per-tool-call credential injection state.
317
+
318
+ ## Local Identity Server (UDS)
319
+
320
+ When `identity.localServer` is `true`, the plugin starts an HTTP server over a Unix Domain Socket, allowing other local processes (scripts, plugins, CLIs) to access identity tokens and execute plugin tools without going through OpenClaw's messaging layer.
321
+
322
+ ### Configuration
323
+
324
+ | Param | Type | Description |
325
+ |-------|------|-------------|
326
+ | `localServer` | boolean | Enable the local UDS server. Default false. |
327
+ | `localServerAllowlist` | string[] | Additional process names or paths allowed to connect. Supports exact match and glob suffix (e.g. `"python*"`). `curl` is always allowed by default. |
328
+ | `localServerFailOpen` | boolean | When peer identity cannot be resolved, allow the connection (relying on 0600 socket permissions). Default true. Set to false for strict mode. |
329
+
330
+ **Socket path**: `~/.openclaw/plugins/identity/identity.sock` (permissions `0600`, owner-only access).
331
+
332
+ ### Endpoints
333
+
334
+ | Method | Path | Description |
335
+ |--------|------|-------------|
336
+ | `GET` | `/token` | TIP token for the main session |
337
+ | `GET` | `/token?session=<key>` | TIP token for a specific session |
338
+ | `GET` | `/session` | OIDC session (id_token) for main session |
339
+ | `GET` | `/status` | Server health and available sessions summary |
340
+ | `GET` | `/tools` | List all available tool names with descriptions and JSON schemas |
341
+ | `POST` | `/tool/<name>` | Execute a registered tool. Body: `{ "params": {...}, "session": "..." }` |
342
+
343
+ ### Peer Credential Checking (Linux)
344
+
345
+ On Linux, the server validates connecting processes via:
346
+
347
+ 1. **`SO_PEERCRED`** (kernel-level): Zero-overhead retrieval of peer PID/UID/GID via `getsockopt`. Requires a registered native provider.
348
+ 2. **`/proc` filesystem**: Derives process name and path from `/proc/<pid>/exe`, `/proc/<pid>/comm`, `/proc/<pid>/status`. No process spawning.
349
+
350
+ Resolved peer info is checked against the built-in allowlist (`curl`) plus any custom entries in `localServerAllowlist`. When `localServerFailOpen` is true (default), unresolvable peers are allowed (socket file permissions provide baseline security).
351
+
352
+ ### Usage Examples
353
+
354
+ ```bash
355
+ # Get TIP token
356
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock http://localhost/token
357
+
358
+ # Get OIDC session token
359
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock http://localhost/session
360
+
361
+ # List available tools
362
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock http://localhost/tools
363
+
364
+ # Execute a tool
365
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock \
366
+ -X POST http://localhost/tool/identity_whoami \
367
+ -H 'Content-Type: application/json' \
368
+ -d '{"params": {}, "session": ""}'
369
+ ```
370
+
371
+ See [`demo/local-server/`](demo/local-server/) for examples in Python, Go, TypeScript, Java, and Rust.
372
+
373
+ ## Data Storage
374
+
375
+ Plugin data at `~/.openclaw/plugins/identity/`:
376
+
377
+ | File | Description |
378
+ |------|-------------|
379
+ | `sessions.json` | Encrypted sessionKey → userToken mapping. Expired entries pruned on load/save. |
380
+ | `credential-env-bindings.json` | Per-session: `{ [sessionKey]: { [provider]: envVar } }` |
381
+
382
+ **In-memory only (not persisted to disk):**
383
+
384
+ | Data | Description |
385
+ |------|-------------|
386
+ | TIP tokens | sessionKey → TIP token cache. Short-lived, re-obtained from session token on demand. |
387
+ | Credentials | Per-session (api_key, oauth2). Lost on gateway restart; cleared on logout. |
388
+ | OIDC state | Ephemeral, 5 min TTL. |
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Agent Identity Plugin
3
+ *
4
+ * - UserPool login via /identity login (OIDC URL returned directly, no HTTP start endpoint)
5
+ * - Credential hosting: list-credentials, fetch <provider>, set <provider> <envVar>
6
+ * - TIP token via AgentIdentity GetWorkloadAccessTokenForJWT in before_agent_start
7
+ * - TIP/session propagation: before_tool_call (sessions_send params.sessionKey), subagent_spawned (sessions_spawn)
8
+ * - Optional AuthZ in before_tool_call
9
+ * - HTTP callback: /identity/oauth/callback (OIDC login). Credential OAuth uses Identity-provided callback.
10
+ * - Tools: identity_whoami, identity_logout
11
+ */
12
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
13
+ declare function registerImpl(api: OpenClawPluginApi): void;
14
+ declare const _default: typeof registerImpl;
15
+ export default _default;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,qBAAqB,CAAC;AAoiC3E,iBAAS,YAAY,CAAC,GAAG,EAAE,iBAAiB,QAmP3C;wBAKwC,OAAO,YAAY;AAA5D,wBAA6D"}