---
summary: "Resolve SecretRefs and give agents curated, audited access to 1Password"
read_when:
  - You want agents to request curated 1Password secrets
  - You want OpenClaw config credentials to resolve from 1Password
  - You need per-secret approval policy and audit history
  - You are configuring a 1Password service account for OpenClaw
title: "1Password"
---

# 1Password

The bundled `onepassword` plugin has two independent, opt-in surfaces:

- a managed exec provider that resolves configured [SecretRefs](/gateway/secrets)
  during Gateway startup, reload, audit, and apply preflight
- a policy-controlled agent tool that reads a curated set of 1Password fields

Both use the official `op` CLI and the same service-account token file. Enabling
the plugin alone does not expose the agent tool: that surface also requires a
configured item registry.

## Security model

- Service-account authentication only. The token stays in a local credentials
  file and is never accepted in `openclaw.json`.
- Curated agent registry only. Agents can list configured slugs, but the plugin
  never enumerates a 1Password vault. SecretRef reads are limited to references
  explicitly stored on registered OpenClaw credential targets.
- Per-slug `auto`, `approve`, or `deny` policy.
- Approval grants expire. A cached value never bypasses current policy.
- Every access attempt is recorded in OpenClaw's shared SQLite state. Audit
  rows include the supplied reason; keep reasons non-sensitive. The broker
  never copies a fetched value or the service token into an audit row.
- After the current tool execution, OpenClaw-owned transcript persistence
  replaces a successful `get` value with redacted metadata.
- The value is model-visible for that execution. If the model copies it into a
  later tool call or reply, that separate record is outside this plugin's
  persistence hook. Keep policies narrow and do not ask the model to echo a
  value.
- The plugin invokes `op` once per cache miss. It does not retry rate limits or
  other failures.
- Each `op` call runs with a minimal environment that disables 1Password
  desktop-app integration (`OP_LOAD_DESKTOP_APP_SETTINGS=false`,
  `OP_BIOMETRIC_UNLOCK_ENABLED=false`), so a 1Password app installed on the
  Gateway host never triggers biometric or macOS permission dialogs.

Give the service account read access only to the vaults and items used by
registered SecretRefs and agent-tool slugs.

## Before you begin

You need:

- the 1Password CLI (`op`) installed on the Gateway host
- a 1Password service account with access to the selected items
- a dedicated service-account token file

Enable the bundled plugin:

```bash
openclaw plugins enable onepassword
```

Create the token directory and file under the OpenClaw state directory:

```bash
mkdir -p ~/.openclaw/credentials/onepassword
chmod 700 ~/.openclaw/credentials/onepassword
printf '%s' "$OP_SERVICE_ACCOUNT_TOKEN" > \
  ~/.openclaw/credentials/onepassword/service-account-token
chmod 600 ~/.openclaw/credentials/onepassword/service-account-token
unset OP_SERVICE_ACCOUNT_TOKEN
```

When `OPENCLAW_STATE_DIR` is set, replace `~/.openclaw` with that directory.
The plugin warns once when the token file is readable or writable by group or
other users.

## Configure SecretRefs

Create a secrets apply plan for common model provider keys:

```bash
openclaw onepassword secretref setup \
  --anthropic-id op://Automation/Anthropic/credential \
  --openrouter-id op://Automation/OpenRouter/credential \
  --plan-out ./openclaw-1password-secrets-plan.json
```

Use `--provider-key <provider=id>` for another model provider, or
`--target <path=id>` for any registered
[SecretRef credential target](/reference/secretref-credential-surface).
The command requires at least one target and writes a plan. Inspect it, check
the local `op` and token-file prerequisites, then apply and reload:

```bash
openclaw onepassword secretref status
openclaw secrets apply --from ./openclaw-1password-secrets-plan.json --dry-run --allow-exec
openclaw secrets apply --from ./openclaw-1password-secrets-plan.json --allow-exec
openclaw secrets audit --check --allow-exec
openclaw secrets reload
```

Before apply, status can report that the provider itself is not configured yet;
`prerequisites ready: yes` confirms that the trusted `op` executable and an
accepted non-empty token file are ready. After apply, `ready: yes` confirms both the
provider wiring and prerequisites. Missing or unsafe prerequisites produce
actionable next steps without printing the token or raw resolver errors.

Manual provider configuration uses the existing plugin id:

```json5
{
  plugins: {
    entries: {
      onepassword: { enabled: true },
    },
  },
  secrets: {
    providers: {
      onepassword: {
        source: "exec",
        pluginIntegration: {
          pluginId: "onepassword",
          integrationId: "onepassword",
        },
      },
    },
  },
  models: {
    providers: {
      openai: {
        apiKey: {
          source: "exec",
          provider: "onepassword",
          id: "op://Automation/OpenAI/credential",
        },
      },
    },
  },
}
```

References use `op://<vault>/<item>/<field>` or
`op://<vault>/<item>/<section>/<field>`. Vault, item, section, and field names
may contain spaces. The setup command stores references that do not fit
OpenClaw's shared exec-id grammar in a plugin-local opaque form and decodes them
only inside the resolver. Very long references should use stable 1Password IDs;
they are shorter and reduce the number of 1Password API requests.

The SecretRef resolver runs at most four `op read` processes concurrently,
disables the 1Password CLI cache so reloads observe rotated values, never uses
desktop-app integration, and does not expose an agent tool for arbitrary reads.
Before passing the service-account token, both plugin surfaces
resolve the executable and reject paths that another local account can replace;
Windows ACL verification must also succeed. Check provider wiring and local
readiness with:

```bash
openclaw onepassword secretref status --json
```

## Configure registered secrets

Add plugin config to `openclaw.json`:

```jsonc
{
  "plugins": {
    "entries": {
      "onepassword": {
        "enabled": true,
        "config": {
          "vault": "Automation",
          "defaultPolicy": "approve",
          "cacheTtlSeconds": 300,
          "grantTtlHours": 720,
          "opTimeoutMs": 15000,
          "items": {
            "repository-token": {
              "item": "Repository automation token",
              "field": "credential",
              "policy": "approve",
              "description": "Token for repository automation",
            },
            "model-key": {
              "item": "Model provider key",
              "vault": "Agent credentials",
              "policy": "auto",
            },
          },
        },
      },
    },
  },
}
```

Slugs use lowercase letters, numbers, and hyphens, start with a letter or
number, and contain at most 64 characters. A registry can contain up to 32
slugs; descriptions can contain up to 200 characters. `field` accepts one field
label or ID, must not contain a comma, and defaults to `credential`.
An item-level `vault` overrides the default vault. `opBin` can set an absolute
path to the `op` executable; otherwise the plugin resolves `op` from `PATH`.
Item titles must not start with a hyphen.

## Use the agent tool

The tool name is `onepassword`.

List registered slugs:

```json
{ "action": "list" }
```

The result contains only the slug, description, policy, and whether a standing
grant is active. It never contains a secret value and does not query 1Password.

Request one secret:

```json
{
  "action": "get",
  "slug": "repository-token",
  "reason": "Authenticate the requested repository operation"
}
```

`reason` is required, must be non-empty, and is limited to 300 characters. A
successful `get` returns the value plus the configured slug, item title, and
field label.

The tool schema also declares an internal `authorizationNonce` parameter. The
policy layer injects it after evaluating the request to hand the authorization
to the executing tool call. Never set it manually: the policy hook overwrites
any supplied value, and an unknown value fails the request.

## Policy tiers and approvals

- `auto`: fetch immediately and audit the request.
- `deny`: block and audit the request.
- `approve`: use an unexpired standing grant, or ask a human to allow once,
  always, or deny.

Allow once authorizes only the current tool call. Allow always writes a standing
grant for that agent and slug to SQLite; other agents must receive their own
approval. OpenClaw offers allow always only when the caller has a concrete agent
identity. The grant expires after `grantTtlHours`, which defaults to 720 hours.
An unresolved or timed-out approval denies the request; the maximum approval
wait is 600 seconds. The plugin retains up to 1,024 standing grants; at that
bound, the oldest grant is evicted and its agent must approve the next access.

Each evaluated authorization is single-use and is handed to the executing tool
call through shared SQLite state, so the handoff also works when more than one
plugin instance is active in the gateway process. Unused authorizations expire
after the 600-second approval window.

The in-memory cache defaults to 300 seconds and is bounded by the configured
slug registry. Set `cacheTtlSeconds` to `0` to disable it. Policy is evaluated
before every cache lookup, and cache hits are audited. Runtime config reloads
take effect at each policy and execution boundary; disabling the plugin or
removing, denying, or retargeting a slug invalidates pending authorization and
cached values.

## Inspect status and audit history

Show readiness and registry counts:

```bash
openclaw onepassword status
```

This reports whether the token file exists, whether `op` resolved and its path,
the registered item count, and per-policy counts. It never reads or prints the
token or secret values.

Show the 50 most recent audit rows:

```bash
openclaw onepassword audit
openclaw onepassword audit --limit 100
```

Rows are newest first and show timestamp, agent, slug, outcome, an `errorCode`
when the attempt failed, and a truncated reason. The reason is stored as
supplied; the broker never adds the fetched value to the audit log.

## 1Password CLI behavior

Each cache miss runs `op item get` with the configured item, vault, and exact
field selector, JSON output, a bounded timeout, and `--cache=false`. The child
receives only that field rather than the full item. Only
`OP_SERVICE_ACCOUNT_TOKEN` and `HOME` are present in the child environment.

The plugin makes one attempt. `RATE_LIMITED` errors should be handled by waiting
before a later agent request; the plugin does not create an automatic retry
loop.

## Error codes

Failed attempts carry one closed error code in the tool result and the audit
row.

1Password access errors:

| Code              | Meaning                                                          |
| ----------------- | ---------------------------------------------------------------- |
| `TOKEN_MISSING`   | Token file is missing or empty                                   |
| `OP_NOT_FOUND`    | `op` binary could not be resolved                                |
| `ITEM_NOT_FOUND`  | Configured item is not in the vault                              |
| `FIELD_NOT_FOUND` | Configured field is not on the item; available labels are listed |
| `RATE_LIMITED`    | 1Password service-account rate limit reached                     |
| `AUTH_FAILED`     | Service-account authentication failed                            |
| `TIMEOUT`         | `op` exceeded `opTimeoutMs`                                      |
| `OP_ERROR`        | Any other `op` failure or invalid output                         |

Policy and validation errors:

| Code                                               | Meaning                                                                      |
| -------------------------------------------------- | ---------------------------------------------------------------------------- |
| `INVALID_ACTION`, `INVALID_REASON`, `INVALID_SLUG` | Request failed input validation                                              |
| `UNKNOWN_SLUG`                                     | Slug is not in the configured registry                                       |
| `TOOL_CALL_ID_MISSING`                             | Call arrived without a tool call id                                          |
| `POLICY_NOT_EVALUATED`                             | No matching authorization for this call; the request was not policy-approved |
| `POLICY_CHANGED`                                   | Config changed between approval and execution                                |
| `GRANT_EXPIRED`                                    | Standing grant lapsed before execution                                       |
| `APPROVAL_CANCELLED`                               | The run was aborted while the approval was pending                           |
