"Store the user's login" sounds like one thing. Build it and it turns into three, and getting the boundaries right is the difference between a system that handles multiple accounts, rotating passwords and vault migrations - and one that needs a migration every time reality shows up.
Credential management for AI agents comes down to modelling the login as three objects, and Wire does exactly that.
| Object | What it is | Relationship |
|---|---|---|
identity | One account, on one site, belonging to one user | holds → |
credential | A stored session, plus the binding that produced it | points at → |
vault item | Lives in your vault. Never copied | (end of chain) |
One credential per (identity, type). The binding lives on the credential - not the identity.
Identity: an account, not a person
An identity is "my account on this supplier's portal." Not a Wire user, not a login to Wire - one account on one site, owned by one user.
The plural is deliberate. Agencies run the same site under many client accounts. A marketplace seller might have a US and an EU account on one platform. Each is its own identity with its own name, and tasks pick between them explicitly. Nothing about the model assumes one account per site.
Credential: the session, and where it came from
A credential is a stored session under an identity. It holds the encrypted cookies, an expiry, and - this is the part that carries weight - a reference to the vault item that produced it.
Wire stores one credential per (identity, credential type), and there are two types:
CREDENTIALS | BROWSER_STATE | |
|---|---|---|
| Produced by | Logging in with a username and password | Importing a browser session directly |
| Holds | Cookies, tokens, and the proxy session that minted them | The captured browser state |
| Pins the exit IP | Yes | No |
| Refreshable from a vault | Yes | Manual re-import |
Because the uniqueness is on the pair, one identity can hold both at once without either clobbering the other. Tasks name the credential they want, so there's no ambiguity about which is in play.
Why the binding lives on the credential
The obvious place to attach "this comes from 1Password item X" is the identity. It's the wrong place.
An identity is the stable thing: this account, on this site. How you authenticate to it is not stable. You might start with a typed password, move to a vault later, migrate from 1Password to Azure Key Vault, or re-point at a different item after a reorganisation. Attach the binding to the identity and every one of those is a change to the account itself - which means everything referencing that account has to care.
Attach it to the credential and those become what they are: the session was minted differently this time. The identity never moves. Tasks referencing it keep working.
There's a safety property too. If an identity is already bound to one vault item and a request arrives binding it to a different one, Wire refuses with IDENTITY_BINDING_MISMATCH rather than silently re-pointing it. Changing which secret backs a live account should take an explicit request, not a side effect.
One binding model, any vault layout
The reference to your vault has to survive a real problem: no two vaults store credentials the same way, and we don't get to impose a convention on a vault you already use.
So the binding supports three shapes:
| How your secret is stored | How Wire binds to it |
|---|---|
| One item with username and password fields | Point at the entry - Wire reads both |
| Password in the value, username in a tag | Map each field to where it actually lives |
| Username and password as two separate secrets | Map each field to its own entry |
All three produce the same thing: a set of fields, resolved at login, in memory. The provider knows how its own vault is laid out. Everything above it just asks for a username and a password.
A binding names an item - not a version. Wire always reads the current value. That single decision is why rotation is invisible: change the password in your vault and the next login uses it, with nothing to update on our side.
Session: the thing that actually does the work
Everything above exists to produce a session and then get out of the way.
Sessions are refreshed as they're used - the runtime writes cookies back after each action, so a site that keeps extending a session keeps it alive without anyone logging in again. When one does lapse, the next task returns AUTH_EXPIRED, and a login request mints a fresh one.
Be precise about that last step: it happens on demand. No background worker is signing into your accounts on a timer. The re-login is triggered by something asking for it - so Wire never reaches into your vault except in response to a request you made, and every one of those reads appears in your vault's own audit trail. Nothing shows up there that you didn't cause.
The exit-IP row deserves a note, because it's the difference that bites in production. A session minted through a login knows which proxy exit it came from, and Wire pins later requests to that same exit. Plenty of sites - particularly commerce platforms and utility portals - invalidate a session that suddenly arrives from a different IP. An imported browser session has no such pin, so it can work perfectly in testing and fail in production for reasons that look like nothing.
If you drive the browser yourself instead of calling a Wire action, Anakin's Browser API saved sessions reuse the session's original exit IP on every load, so logins protected by IP binding stay valid.
What the shape buys you
- Many accounts per site - each an identity, chosen per task.
- Rotation with no coordination - bindings name items, not versions.
- Vault migration without touching accounts - re-bind the credential, and the identity stays where it is.
- Deletion at the granularity you need - drop a session, an account, or a whole vault connection.
- Nothing worth stealing - a reference and an encrypted session, per site, self-expiring.
So "store the user's login" really is three things: an account that never moves, a session that comes and goes, and a pointer into a vault you already run. Keep them apart and reality stops forcing a migration.
Frequently Asked Questions
What is the difference between an identity and a credential in Wire?
An identity is one account on one site, owned by one user. A credential is a stored session under that identity: the encrypted cookies, an expiry, and, for a vault-backed login, a reference to the vault item that produced it.
Can an AI agent use more than one account on the same site?
Yes. Each account is its own identity with its own name, so an agency can hold many client accounts on one site and a seller can keep a US and an EU account side by side. Each task names the credential it wants.
Which password vaults can Wire read logins from?
1Password and Azure Key Vault. Wire resolves the username and password fields from the bound vault entry at login, in memory, and stores the resulting session rather than the password.
What happens when a password is rotated in the vault?
If the binding doesn't pin a specific version, Wire reads the current value of the vault item, so the next login uses the new password with nothing to update in Wire.
What does AUTH_EXPIRED mean?
The credential's session is no longer valid, for example because the cookies expired or the password changed. Send a login request for that identity and Wire refreshes its stored session in place.
Go deeper. The identity and credential endpoints, including every field described here, are documented in full. The next post shows how we prove a password never reaches a log line.
