Skip to main content
a vault-attached browser can get a login from two places. KERNEL can store the values in a credential item, or a user can approve access to logins that stay in their 1Password account.

Choose a path

you or your agent must ask the end user whether they want to use 1Password for the website’s login. if they choose 1Password, link their 1Password account and request the login through 1Password brokered approval. if they don’t, or if that path doesn’t produce a usable login for any reason, your application should tell the user that 1Password did not work and fall back to KERNEL-hosted collection. see fall back to KERNEL-hosted collection for when to switch. keep in mind the limits of 1Password’s api: the login must be in a private vault that isn’t shared, and passkeys aren’t supported. if the user’s login is in a shared vault or the user signs in with a passkey, fall back to KERNEL-hosted collection. neither path confirms that the website accepted the login. check the page after filling.

KERNEL-hosted credential collection

KERNEL-hosted collection works for any user and is the fallback. create a credential item with provider: "kernel", present its collect action to the user, then invoke fill. see credential items for the full flow.

1Password brokered approval

brokered approval uses 1Password’s Agentic Autofill. the user reviews each access request in the 1Password app on their own device and chooses which logins to grant. the 1Password browser extension, which KERNEL takes care of loading into the vault-attached browser, then fills the granted login into the page. credential values are never returned by KERNEL’s api or passed through your application or model context. check 1Password’s supported accounts, vaults, and apps before you plan a rollout.

How credentials are protected

  • the user chooses the exact logins to grant in the 1Password app.
  • KERNEL stores encrypted connection material and credential references in its items, not the login values.
  • the 1Password extension fetches the credential and fills it into the page. KERNEL’s api returns a status, never the values.
  • KERNEL checks that the page shares the origin of an approved login before it fills.
  • KERNEL locks the browser while the values are in the page. see fill and submit.
  • on fillFailed or autosubmitFailed, the extension clears what it filled before it returns.
  • the destination website necessarily receives the credential, and its scripts can observe it.
  • use a dedicated browser for each user, and don’t load extensions you don’t trust.

Choose an OAuth client

every 1Password connection belongs to an oauth client. 1Password shows the client’s name and icon on the consent screen and in the approval prompt, so the choice decides what your users see and how much of the account linking flow you need to build yourself. start with the KERNEL-managed oauth client: it’s the quickstart, and KERNEL runs account linking for you. your own oauth client is an advanced option for when your users must see your integration’s name and icon and you can run the oauth flow yourself. tell your users that KERNEL is the browser provider that fills their logins through the 1Password extension, and that neither KERNEL nor your agent handles the login values. then:
  1. create a credential_account item to link the user’s 1Password account. see connect a 1Password account.
  2. create a credential item with account set to that item’s key to describe the login you need. see define a login request.
  3. in a vault-attached browser, invoke 1pw_create_access_request, give the user the approval link, and poll 1pw_access_request_status. see request access and hand off approval.
  4. once the user approves, invoke 1pw_fill on that item in a browser session. see fill and submit.

Your own OAuth client (advanced)

you’re responsible for the full account linking flow. follow 1Password’s guides:
  • register an oauth client with an https redirect uri. see go to production.
  • run the authorization code flow with pkce (S256) and validate state. see connect a user.
  • capture the integration key from your callback’s url fragment, exchange the code, and refresh the access token from your backend. see store keys and tokens.
  • revoke the connection when the user disconnects. see disconnect a user.
then:
  1. create a credential item with the user’s access_token and integration_key to describe the login you need. see use your own oauth client.
  2. before each task, refresh the access token on your backend and send it with 1pw_update_access_token. see replace a stored access token.
  3. in a vault-attached browser, invoke 1pw_create_access_request, give the user the approval link, and poll 1pw_access_request_status. see request access and hand off approval.
  4. once the user approves, invoke 1pw_fill on that item in a browser session. see fill and submit.
on either path, if a step doesn’t produce a usable login, fall back to KERNEL-hosted collection. KERNEL never refreshes or revokes a token you supply. your refresh token and client secret stay in your backend; KERNEL never needs them.

Connect a 1Password account

create a credential_account item in the user’s vault. it returns state.status: "pending_authorization" and an action named 1password_oauth. present action.url to the signed-in user in your application, outside the agent-controlled browser. the user signs in to 1Password and approves the connection. this path uses KERNEL’s oauth client; credential_account items don’t accept a custom one. to use your own client, skip the account and supply your own tokens.
KERNEL receives the oauth callback, exchanges the code, stores the connection encrypted, and refreshes its tokens. the api never returns tokens or other connection secrets. the authorization url expires after a short time. repeating the same upsert returns the current url while it’s valid and issues a new one after it expires. a wait read keeps holding while the status is reconnect_required, so check the status instead of waiting for it to change. if linking the account fails in a way KERNEL can recover from, the credential_account advertises 1pw_recover and state.status_reason describes the failure. invoke it to get a new 1password_oauth action, and present its url to the user as you did when connecting. after recovery completes, start a new authorization on the same item by repeating the account upsert. don’t delete the account to recover, and don’t retry recovery automatically.

Define a login request

create a credential item with provider: "1password" and account set to the key of a connected credential_account in the same vault. the item stores the account’s key, not its id, and returns it in spec.account. requests uses 1Password’s version 2 credential request format with one to five login entries, each with an https website. the item stores no values or selectors.
goal accepts up to 140 characters, each entry’s reason up to 100, and an entry can include one to five keywords of up to 50 characters each. the new item starts in pending_authorization and advertises 1pw_create_access_request. the source, account, and requests are immutable; repeating the same upsert returns the current item, and a different spec at the same key returns 409. use a new item key for different logins. the deprecated website shorthand is still accepted for account-backed items, but supply requests for new items.

Use your own OAuth client

instead of account, supply the user’s access_token and the matching integration_key that your oauth client received from 1Password. KERNEL checks that they belong together, stores both encrypted on this item, and never returns either. set access_token_expires_at from the token response’s expires_in so KERNEL knows when the token stops working; it must be in the future, and the item returns it in spec.access_token_expires_at. these items require requests.
supply account or both secrets, never both; a mismatched or incomplete pair returns 400. repeating the create with identical values returns the current item. a create at the same key with a different token, key, expiry, or requests returns 409, so don’t use the upsert to rotate the token. after access_token_expires_at passes, the item stops advertising 1pw_create_access_request, 1pw_access_request_status, and 1pw_fill, and 1pw_fill returns 409 until you replace the token. the token response and integration key in these samples stand for values your backend already holds; don’t pass them through a model.

Replace a stored access token

1Password access tokens are short-lived, so refresh the token on your backend as 1Password describes and invoke 1pw_update_access_token with the new access_token before you request access, poll, or fill. the new token must match the stored integration key. the operation replaces only the token: the integration key, requests, pending access request, approved references, and state.status stay as they were. set access_token_expires_at to record the new expiry, or omit it to clear the old one.
stored-token items advertise 1pw_update_access_token whenever no other 1Password operation is in progress; during one, it returns 409. updating the token doesn’t contact 1Password and doesn’t retry a pending or uncertain operation.

Request several logins

a requests object can hold up to five login entries, so one approval can cover several logins. the user can approve some entries and not others. when approved entries share an origin, pass entry_id to 1pw_fill to choose one. reason and keywords overrides at request time work only when the item has a single entry.

Request access and hand off approval

create a browser with the vault attached, then invoke 1pw_create_access_request with its browser_id. you don’t install anything: KERNEL loads the 1Password extension into that browser on demand the first time an operation needs it, then creates the access request through the extension. goal, reason, and keywords in the operation override the item’s values for this request.
the response returns an action named 1password_access_approval. its url is a native onepassword://grant-brokered-access link and instructions describes the handoff. present the link to the end user who owns the 1Password account. they open it on the device where they use the 1Password app, choose the logins, and approve or deny there. the link grants nothing until they approve. 1Password closes the unlock and approval prompts after 2 minutes; if the user doesn’t finish, create a new credential item to send a new request. an item accepts only one open access request. the approval link carries your goal, reasons, and websites. don’t log it, don’t pass it through a model, and deliver it to the user’s device over an authenticated channel. see 1Password’s approval guide. state.access_request reports non-secret request state, such as its id, state, entries, granted_count, and whether a fillable reference exists (has_autofill_token). other fields are echoed from 1Password’s response when it supplies them. don’t automatically retry a failed request. if the call fails before KERNEL dispatches the request to 1Password, the item still advertises 1pw_create_access_request. if it fails after dispatch, the outcome is uncertain: a request might exist in 1Password. the item stays blocked in pending_authorization with no approval action and no available operations, and KERNEL doesn’t offer a way to retry or reset it. ask the account owner to check the 1Password app for a pending request instead of sending another.

Poll for the decision

after you present the approval link, invoke 1pw_access_request_status with a vault-attached browser_id until the status leaves pending_authorization. timeout_seconds accepts 0–120 and defaults to 10. KERNEL records the decision only when you poll; a wait read of the item doesn’t observe approval.
declined and failed are final for the item; use a new key to request again. an item with several entries also moves to failed if 1Password doesn’t report which approved login belongs to which website; state.status_reason then recommends separate credential items. if 1Password resolves a single-entry request without exactly one matching login, the item returns to pending_authorization, state.status_reason explains why, and you can invoke 1pw_create_access_request on the same item again. approved references stay encrypted and are only usable by 1pw_fill. ready means an approval was recorded, not that 1Password will honor it indefinitely.

How long a grant lasts

the user approves once per login, not once per fill. while the grant lasts, 1pw_fill can fill that login as often as the task needs without prompting the user again.
  • at launch, 1Password keeps a grant valid for 30 days. configurable lifetimes are planned.
  • a grant isn’t tied to a session or task. if you promise your users approval per session, create a new credential item and access request for each session.
  • a grant ends sooner if the connection is revoked or expires. a connection lasts about 90 days at most, and less if its tokens stop being refreshed.
  • KERNEL doesn’t track the grant’s lifetime, so the item stays ready after the grant ends and fills fail. to ask again, create a new credential item; a ready item doesn’t accept another access request.
see 1Password’s how long a grant lasts and how long a connection lasts.

Fill and submit

navigate the attached browser to the page with the username and password form, not a page that asks the user to choose a sign-in method. then invoke 1pw_fill with the browser’s session id and the exact current top-level page_url. the url must match exactly one open page and share the origin of an approved entry. when more than one approved entry has that origin, pass its entry_id from state.access_request.entries. the extension selects the fields, fills them, and submits the form; you can’t supply selectors or values. fill_submitted means the extension reported that it submitted the form. if the extension fills the form but can’t submit it, it clears what it filled and KERNEL returns fill_failed. a submitted form doesn’t mean the login succeeded. for a sign-in that spans several pages, such as a username page, a password page, and a one-time password page, invoke 1pw_fill again on each page. each page must share the origin of the approved entry, and every fill is a new request to 1Password, so an ended grant fails at the next fill.
exclusive browser control during autofill: while 1pw_fill runs, KERNEL gives the autofill operation exclusive control of the browser. new CDP, WebDriver, and browser api requests are rejected with 423 Locked, and existing control connections are interrupted, not paused. reconnect after the call returns. only KERNEL’s autofill connection can control the browser until 1pw_fill returns.this prevents concurrent automation from reading the page while credential values are present. it does not isolate credentials from the destination page, its scripts, or other extensions in the browser. live view isn’t part of the lock: anyone with the browser’s live view can watch and send input during the fill, so don’t share it with anyone who shouldn’t see the login.
for an item with one entry, omit entry_id. timeout_ms accepts 1–30,000 and defaults to 30,000.

Fall back to KERNEL-hosted collection

when the 1Password path can’t give you a usable login, create a separate credential item with provider: "kernel" and collect the login from the user instead. switch when:
  • the user doesn’t want to use 1Password, the login is in a shared vault or is a passkey, or their account isn’t in 1Password’s supported list.
  • account linking doesn’t reach connected, for example because the user declined consent.
  • the access request ends declined or failed, or the user doesn’t approve it before the prompt closes.
  • 1pw_fill keeps returning fill_failed on the website’s login form.
  • a stored access token can’t be refreshed or the grant has ended, and the user doesn’t want to connect or approve again.
after fill_unknown, check the page before you fall back; the extension might already have submitted the form. tell the user why you’re asking for the login again.

Delete items

delete a 1Password credential item to discard its approval references and, for a stored-token item, its encrypted token and key. delete every credential item that references an account before deleting the credential_account; otherwise the api returns 409. deleting the account removes KERNEL’s stored connection. deleting either item doesn’t remove the connection or revoke the token in the user’s 1Password account. if you use your own oauth client, revoke the connection from your backend when the user disconnects; see 1Password’s disconnect guide.

Limitations

  • not secret isolation: for each access request, status check, and fill, KERNEL gives the extension inside the attached browser access to the connected account or supplied token, and it doesn’t remove the extension afterward. use a dedicated browser for 1Password operations, don’t give untrusted automation access to it, and don’t load extensions you don’t trust alongside it. the filled values are in the page between fill and submit.
  • private vaults only, no passkeys: 1Password’s api can grant only logins stored in the user’s private, non-shared vault, and it doesn’t support passkeys. see 1Password’s supported list.
  • grants expire: 1Password grants last 30 days at launch and end sooner if the connection ends. ready doesn’t expire with them; see how long a grant lasts.
  • up to five logins per item: each credential item carries one to five https login entries.
  • you manage your own oauth client’s tokens: KERNEL doesn’t refresh or revoke a supplied access token. refresh it on your backend and replace it with 1pw_update_access_token before each task.
  • submission isn’t authentication: fill_submitted means the form was submitted, not that the login succeeded. confirm the result on the page.
  • no automatic retries: access requests, recovery, and inconclusive fills can have effects in 1Password or on the website. an access request with an uncertain outcome stays blocked; don’t send another automatically.