Skip to main content
Partner preview Your web app can present an access request to 1Password without sending the person to the 1Password app. Your page opens 1Password.com in a popup and passes it the access request reference you got when you created the request. The person signs in, chooses which logins to grant, and approves or denies. The popup posts the answer back to your page. Your page receives references to the granted logins, never a password.
Approval in the browser is in development and isn’t available to test yet. You can build your side against this page now. 1Password will let you know in your shared Slack channel when the surface is ready to test end to end.

How it works

  1. Your page opens https://my.1password.com/grant-access in a popup, with your page’s origin and the access request reference.
  2. 1Password checks that the origin matches your OAuth client’s redirect URI, and the person signs in to the account they connected.
  3. The person grants or denies the request.
  4. The popup posts one grantBrokeredAccess message to your page through window.opener, then closes.
  5. You confirm the outcome with a status check from your backend.

Before you start

Serve your page from your redirect URI’s origin. 1Password answers only a page whose origin exactly matches the origin of your OAuth client’s redirect URI: scheme, host, and port, with the path ignored. A client has one redirect URI, so serve your approval page from the same origin as your OAuth callback. If your redirect URI is https://app.partner.example/oauth/callback, open the popup from a page on https://app.partner.example. Get the access request reference. It’s the access_request_reference value in the appLink returned when you create the request, by the browser extension’s createAccessRequest or by the SDK’s accessRequests.create.
Pass the reference unchanged. Like the approval link, it carries your request text, so keep it out of logs and model context, and send it only to the signed-in person’s own page over HTTPS.

Open the popup

Open this URL in a popup, from a click handler:
The host is the web origin, https://my.1password.com, for everyone, whatever the person’s account address. See Base URLs and endpoints.
Two things make sure the answer reaches your page:
  • Keep window.opener. 1Password posts the answer through it. Don’t pass noopener or noreferrer to window.open, don’t serve your page with Cross-Origin-Opener-Policy: same-origin, and don’t redirect your own tab to the URL instead of opening a popup.
  • Call window.open directly in the click handler. Calling it after an await can trip popup blockers. Create the access request first, then show an Approve in 1Password button that opens the popup.
In the popup, the person signs in to the account they connected, then grants or denies the request. After they decide, the popup closes itself. After an error, it stays open and explains what went wrong.

Receive the answer

Listen for message events on the page that opened the popup. Check every message before you trust it, and ignore everything else.
The popup posts at most one grantBrokeredAccess message, and your page never sends anything to the popup. The message has this shape:
The 2-minute timer starts when the prompt appears, so signing in doesn’t use it up. If the person closes the popup before the prompt appears, while signing in or loading, the popup posts nothing. Watch popup.closed to catch that case.

The authorized payload

accessRequestStatus is a JSON string. Parse it to get the access request’s state and the granted logins:
The payload carries references only, never item data. entryId names the request entry the login satisfies, and is null for a login the person added beyond the ones you asked for. Match on entryId, never on position. Each reference is nested as reference.reference: pass that inner string, unchanged, to the extension’s fillCredential or to the SDK’s read methods. See Read what the person granted.

Errors

When status is error, error is one of these codes: account_not_found and request_unavailable aren’t sent yet. Those cases arrive as internal_error or invalid_request for now. Handle every code anyway, and treat a code you don’t recognize like internal_error.

Confirm on your backend

Treat the popup’s answer as a signal to check the request’s status, not as the result. The status from the SDK’s accessRequests.getStatus, or the extension’s getAccessRequestStatus, is authoritative, and the two can differ:
  • cancelled, but granted. If the person closes the popup while their approval is being submitted, your page hears cancelled, but the grant can still complete.
  • denied, but still pending. 1Password posts denied even if it couldn’t record the denial, so the request can stay pending.
When the popup answers, or closes without answering, check the status from your backend and act on that. See Wait for the decision.

If no answer arrives