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
- Your page opens
https://my.1password.com/grant-accessin a popup, with your page’s origin and the access request reference. - 1Password checks that the origin matches your OAuth client’s redirect URI, and the person signs in to the account they connected.
- The person grants or denies the request.
- The popup posts one
grantBrokeredAccessmessage to your page throughwindow.opener, then closes. - 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 ishttps://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.
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.
- Keep
window.opener. 1Password posts the answer through it. Don’t passnoopenerornoreferrertowindow.open, don’t serve your page withCross-Origin-Opener-Policy: same-origin, and don’t redirect your own tab to the URL instead of opening a popup. - Call
window.opendirectly in the click handler. Calling it after anawaitcan trip popup blockers. Create the access request first, then show an Approve in 1Password button that opens the popup.
Receive the answer
Listen formessage events on the page that opened the popup. Check every message before you trust it, and ignore everything else.
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:
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
Whenstatus 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’saccessRequests.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 hearscancelled, but the grant can still complete.denied, but stillpending. 1Password postsdeniedeven if it couldn’t record the denial, so the request can staypending.