Automating anything behind a login usually creates an awkward credential problem. Someone exports a password into an env var, a CI secret, or a database column. It works for a while, then the password rotates, the owner leaves, or the account gets locked because an old copy keeps retrying.
The better pattern is to avoid copying the credential at all. Give the automation its own scoped access to a password manager, store a reference to the item it needs, and read the secret only at the moment of use.
Use a service account, not a human account
A 1Password Service Account exists for machine access. It can access specific vaults, and you can revoke it without changing any person's account.
That matters more than it sounds. If you automate with a human login, you inherit everything messy about that user:
- The automation can see everything the user can see.
- Password changes can break jobs without warning.
- Offboarding the user breaks the integration.
- Audit logs point at the person, not the system doing the work.
A cleaner setup is a dedicated vault, for example Automation Logins, containing only the accounts your automation should use. Then create a Service Account with access to that vault and nothing else.
You can sanity check the scope with the 1Password CLI before wiring it into an app:
# Paste the token when prompted, rather than putting it in shell history
read -s OP_SERVICE_ACCOUNT_TOKEN
export OP_SERVICE_ACCOUNT_TOKEN
# Confirm the service account sees only the vaults you expect
op vault list --format json | jq -r '.[].name'
# Confirm a target item has standard Login fields
op item get 'Supplier Portal' \
--vault 'Automation Logins' \
--format json \
| jq -r '.fields[] | select(.label == "username" or .label == "password") | .label'
If that command lists vaults you did not expect, fix the Service Account before doing anything else.
Wire uses this scoped Service Account pattern for login automation: the 1Password connection grants access to selected vaults, while each automated identity points at a specific login item.
Store references, not password copies
The important design choice is what your application stores.
Avoid this:
create table automated_identity (
id uuid primary key,
username text not null,
password_ciphertext bytea not null
);
That schema creates a second source of truth. Once you copy the password, you own rotation, expiry, retry behavior, and cleanup. If the password changes in 1Password, your copy becomes stale. The failure often shows up later as repeated login failures, sometimes ending in an account lockout.
Prefer this:
create table credential_source (
id uuid primary key,
provider text not null,
encrypted_service_account_token bytea not null,
status text not null check (status in ('active', 'revoked'))
);
create table automated_identity (
id uuid primary key,
credential_source_id uuid not null references credential_source(id),
vault_id text not null,
item_id text not null
);
The identity stores a pointer: source, vault, item. It does not store the username or password. At login time, the app resolves the pointer, reads the current item from 1Password, uses the credential in memory, and discards it.
That one change makes rotation much less dramatic. Change the password in 1Password and the next login reads the new value. Existing web sessions may keep working until they expire because the target site already issued them, but the next sign-in does not need a database update or redeploy.
Know what the token grants
A 1Password ops_... token is not just a random API key. 1Password uses end-to-end encryption, so the token carries the material needed by the client SDK to authenticate and decrypt items the Service Account can access.
Treat it like a high-value secret:
- Store it encrypted at rest.
- Do not log it.
- Do not put it in shell history.
- Do not reuse it across environments unless you want shared blast radius.
- Prefer separate Service Accounts for dev, prod, clients, or teams.
The token does not grant access to every vault in the 1Password account. It grants access to the vaults assigned to that Service Account. That is why scoping at creation time matters.
A useful implementation detail: verify the token before saving it. Make a live call to 1Password, list the accessible vaults, and only persist the encrypted token if that succeeds. Otherwise you end up with a connection record that looks configured but fails on first use.
Handle failure as state, not mystery
Credential integrations fail in predictable ways. Model those failures explicitly.
Common cases:
| Error | Usually means | Fix |
|---|---|---|
SOURCE_TOKEN_REJECTED |
Token was revoked, rotated, expired, or mistyped | Re-enter or replace the Service Account token |
SOURCE_ITEM_NOT_FOUND |
Item was deleted, moved, or the stored item id is wrong | Rebind the identity to the correct item |
SOURCE_ITEM_MISSING_FIELDS |
The item is not a standard Login item, or lacks username/password fields | Convert or recreate it as a Login item |
SOURCE_REVOKED |
The Service Account no longer works | Mark dependent identities broken until reverified |
The third one catches teams often. A Secure Note can contain text that looks like a username and password, but your integration may read only standard Login fields. If the item looks right in the UI but the SDK cannot find fields, check the item type.
Wire marks a 1Password source as revoked after a rejected read, so dependent identities fail visibly instead of retrying stale credentials in the background.
Revocation should not require vendor cooperation
The clean revocation path should start in the password manager. Delete or disable the Service Account in 1Password, and future reads should fail immediately.
Your app still needs to handle already-issued sessions. If the automation logged into a website yesterday, that site may keep accepting the session cookie until it expires. Revoking the Service Account prevents new password reads, but it does not automatically invalidate sessions held by third-party sites.
If you need immediate cutoff, do both:
- Revoke the Service Account so no new credentials can be read.
- Delete stored sessions in your automation system, or sign out all sessions on the target site.
The practical next step: create a dedicated 1Password vault with one non-critical test login, grant a Service Account only that vault, validate it with the CLI, then build your automation around item references rather than copied passwords.
Top comments (0)