> ## Documentation Index
> Fetch the complete documentation index at: https://www.1password.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a connect link

> Send people one link that starts a 1Password sign-up if they're new, and connects their account inside 1Password for iOS if they already have the app.

export const StatusBadge = ({children}) => <span className="op-status-badge not-prose">{children}</span>;

<StatusBadge>Partner preview</StatusBadge>

A connect link is one `https` link for everyone your agent asks to connect 1Password, whether or not they have 1Password yet. It carries two sets of parameters: the person's details for sign-up, and the same OAuth request you send to the [authorize endpoint](/agentic-autofill/partners/connect#start-authorization).

What happens when the person opens it depends on their device:

* **1Password for iOS is installed:** 1Password opens and shows the consent screen in a sheet, already signed in. When the person answers, iOS returns them to your app with the usual callback.
* **Anywhere else:** the link opens in the browser and starts a new 1Password account for the person, with their name and email filled in.

<Warning>
  Pre-release. Connect links are in development, and the parts reach each environment at different times. Check [Availability](#availability) before you ship one. Details may change.
</Warning>

## Availability

| Part | Status |
| - | - |
| Sign-up in the browser | In production at `start.1password.com`, once 1Password turns it on. Ask your 1Password contact whether it's on before you depend on it. |
| Connect inside 1Password for iOS | In development. It needs a 1Password for iOS release that supports connect links. Until then, the link goes to sign-up in the browser on iPhone and iPad too. |
| 1Password for Android, Mac, and Windows | Not supported yet. The link goes to sign-up in the browser. |

## Build the link

Build connect links in your backend, the same way you build an authorization URL. The link needs the `state` and PKCE values you create there, and the code verifier stays on your server.

```text theme={null}
https://start.1password.com/sign-up/agent/individual
  ?name=<the person's name>
  &e=<the person's email address>
  &agent=<your agent ID>
  &response_type=code
  &client_id=<client_id>
  &redirect_uri=<your redirect URI, URL-encoded>
  &scope=brokered-credentials%3Arequest-access%20brokered-credentials%3Aread
  &state=<opaque value you generate>
  &code_challenge=<base64url SHA-256 of the code verifier>
  &code_challenge_method=S256
```

The host is `https://start.1password.com`.

### Sign-up parameters

<ParamField query="name" type="string" required>
  The person's name, for their new 1Password account.
</ParamField>

<ParamField query="e" type="string" required>
  The person's email address. 1Password sends the verification email to it. In 1Password for iOS, it also picks the account to connect when the person has more than one.
</ParamField>

<ParamField query="agent" type="string" required>
  The agent ID 1Password assigned to your product. It attributes the sign-up to your product, and the verification email names your product. Ask your 1Password contact for yours. IDs that 1Password didn't assign aren't accepted.
</ParamField>

<ParamField query="l" type="string">
  The language for the sign-up pages, such as `en`.
</ParamField>

Send `name`, `e`, and `agent` every time. If any of them is missing, or `agent` isn't an ID 1Password assigned, the browser opens the regular 1Password sign-up page instead. Only the email is filled in there, and the sign-up isn't attributed to your product.

### OAuth parameters

Send the same seven parameters as the authorize endpoint, with the same rules. See [Start authorization](/agentic-autofill/partners/connect#start-authorization).

* Include all seven, each exactly once, with a value.
* Use a `redirect_uri` that's registered on your OAuth client and uses `https`.
* Generate a new `state` and code verifier for every link, and keep them with the person's pending connection, as you do for an authorization URL.

If a parameter is missing, empty, or repeated, 1Password can't connect the person in the app, and the link goes to sign-up in the browser.

### Encode every value

Percent-encode each value, with `encodeURIComponent` or your language's equivalent.

* Encode a `+` in an email address as `%2B`. An unencoded `+` is read as a space, and the email address is wrong.
* Encode the space between the two scopes as `%20`.
* Encode `redirect_uri` as one value, so its own `?`, `&`, and `/` characters don't break the link.

```typescript connect-link.ts theme={null}
const CONNECT_LINK_ORIGIN = "https://start.1password.com";

export function buildConnectLink(input: {
  name: string;
  email: string;
  agentId: string;
  clientId: string;
  redirectUri: string;
  state: string;
  codeChallenge: string;
}): string {
  const params: [string, string][] = [
    ["name", input.name],
    ["e", input.email],
    ["agent", input.agentId],
    ["response_type", "code"],
    ["client_id", input.clientId],
    ["redirect_uri", input.redirectUri],
    ["scope", "brokered-credentials:request-access brokered-credentials:read"],
    ["state", input.state],
    ["code_challenge", input.codeChallenge],
    ["code_challenge_method", "S256"],
  ];
  const query = params
    .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
    .join("&");
  return `${CONNECT_LINK_ORIGIN}/sign-up/agent/individual?${query}`;
}
```

Assembled, a connect link looks like this:

```text theme={null}
https://start.1password.com/sign-up/agent/individual?name=Sam%20Rivera&e=sam%2Btravel%40example.com&agent=<agent-id>&response_type=code&client_id=A1B2C3D4E5F6G7H8J9K0LMNPQR&redirect_uri=https%3A%2F%2Fpartner.example.com%2Fcallback&scope=brokered-credentials%3Arequest-access%20brokered-credentials%3Aread&state=7f3c1e9a2b5d4f80&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256
```

## Open the link

* **Open it as a page load in the person's browser.** A tap on the link works, and so does your app opening the URL. 1Password only starts a sign-up for a top-level page load. A server-side request, `fetch`, an iframe, a link preview, or a prefetch gets a redirect to the regular sign-up page and creates nothing.
* **On iOS, open it with the system URL handler,** such as `UIApplication.shared.open`, so iOS can hand it to 1Password. A link loaded inside a web view shows the web page instead.
* **Keep it out of logs and model context.** The link carries the person's name and email address. Hand it from your backend to your app in code, as you do the approval link.

## What the person sees

### In 1Password for iOS

This path is in development. See [Availability](#availability).

1. 1Password opens. If it's locked, the person unlocks it.
2. 1Password picks the account to connect: the unlocked account whose email address matches `e`, or the only unlocked account. If neither applies, the person chooses one.
3. The consent screen opens in a sheet, already signed in, so the person doesn't enter their password. They answer on the consent screen.
4. 1Password closes the sheet and hands your redirect URI to iOS. iOS opens your app if your app claims that URL as a universal link. Otherwise it opens the URL in Safari.

If 1Password can't connect the account in the app, it opens the consent screen in the browser instead. If no account is signed in to the app, it opens sign-up in the browser.

### In the browser

1. 1Password starts an Individual account sign-up for the name and email address in the link, and asks the person to verify their email address.
2. The verification email names your product. The person verifies their email address from the email.
3. The person sets their account password and saves their Secret Key.
4. The person lands in their new account on 1Password.com.

Sign-up in the browser doesn't connect the new account to your product: this path doesn't use the OAuth parameters. After the person has an account, connect them with the [authorization URL](/agentic-autofill/partners/connect#start-authorization). To approve requests, they also need the 1Password app. See [Where the person can approve](/agentic-autofill/partners/approval#where-the-person-can-approve).

The browser path always starts a new account. It doesn't sign in someone who already has 1Password. Give people who already use 1Password a way to connect with the authorization URL, such as an "I already have 1Password" option next to your connect link.

## Handle the result

When the person answers in 1Password for iOS, your redirect URI receives the same callback as the authorize endpoint: `code` and `state` in the query string, `integration_key` in the fragment on a first connection, and `error=access_denied` if the person declines. See [Handle the callback](/agentic-autofill/partners/connect#handle-the-callback). The code exchange doesn't change.

* **In your app:** when iOS opens your app with the redirect URL, your app receives the whole URL, fragment included. Read `integration_key` from the fragment and store it before anything else that can fail.
* **In Safari:** make the page at your redirect URI handle the same URL in a browser, for people whose device doesn't open your app.

## Checklist

* An agent ID from your 1Password contact.
* Connect links built in your backend, with a new `state` and code verifier for each one.
* `name`, `e`, and `agent` in every link, and all seven OAuth parameters, each once.
* Every value percent-encoded, including `+` as `%2B` in email addresses.
* Links opened with the system URL handler, not loaded in a web view.
* A redirect URI your app claims as a universal link, with a page at the same URL that handles the callback in a browser.
* A way for people who already use 1Password to connect with the authorization URL.
* A connect step after sign-up in the browser.


## Related topics

- [Build integrations with 1Password](/get-started/build-integrations.md)
- [Use the 1Password Terraform provider with Connect](/connect/terraform.md)
- [Use 1Password CLI with Connect](/cli/connect.md)
