---
title: "Link a provider login only to an account · Agent Wranglers"
url: https://agentwranglers.se/playbook/accounts/sign-in-methods/link-provider-login
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Link a provider login only to an account its owner controls

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Sign-in methods](https://agentwranglers.se/playbook/accounts/sign-in-methods.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- Level: Required
- Chapter: [Sign-in methods](https://agentwranglers.se/playbook/accounts/sign-in-methods)
- Rule: Never join a provider login to an existing account because the email addresses match. Link it after the person signs in to that account, or under the trusted-issuer exception below.
- Risk: An account or system taken over
- Applies when: The project has user accounts.
- How: When a new provider login carries the email of an existing account, sign the person in to nothing. Ask them to sign in the usual way, then connect the provider from settings. The one exception is a provider on your own list of issuers trusted for email, with `email_verified` true, when your account's email is verified too. OpenID Connect leaves the meaning of `email_verified` to each provider, so keep that list short and written down. Show every linked login in settings with its provider and the date it was added. This closes the takeover in [stop strangers from claiming an address before its owner](https://agentwranglers.se/playbook/accounts/sign-up/pre-hijacking).
- Check: On staging, sign in through a provider not on the trusted list, with the email of an existing account. No link is made and the sign-in page asks for the existing account. Repeat with `email_verified` false from a trusted issuer. No link is made either.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
const ISSUERS_TRUSTED_FOR_EMAIL = new Set(['https://accounts.google.com']);

export function mayLinkByEmail(claims, existingUser) {
  return ISSUERS_TRUSTED_FOR_EMAIL.has(claims.iss)
    && claims.email_verified === true
    && existingUser.emailVerified === true;
}
```

### Python example

```python
ISSUERS_TRUSTED_FOR_EMAIL = {"https://accounts.google.com"}

def may_link_by_email(claims: dict, existing_user) -> bool:
    return (
        claims.get("iss") in ISSUERS_TRUSTED_FOR_EMAIL
        and claims.get("email_verified") is True
        and existing_user.email_verified
    )
```

## Sources

- [OpenID Connect Core 1.0 on claim stability](https://openid.net/specs/openid-connect-core-1_0.html#ClaimStability)
- [OpenID Connect Core 1.0 on standard claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)

## Related rules

- [Stop strangers from claiming an address before its owner](https://agentwranglers.se/playbook/accounts/sign-up/pre-hijacking) in Accounts
- [Never remove the last way to sign in](https://agentwranglers.se/playbook/accounts/sign-in-methods/last-sign-in-method) in Accounts

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/accounts/sign-in-methods/link-provider-login">Agent Wranglers accounts playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Let people sign in with an account they already have](https://agentwranglers.se/playbook/accounts/sign-in-methods/provider-sign-in)
- Next: [Accept long passwords and refuse breached ones](https://agentwranglers.se/playbook/accounts/sign-in-methods/password-rules)
- [Sign-in methods](https://agentwranglers.se/playbook/accounts/sign-in-methods)
