← Back to blog

Link and unlink OAuth providers with Own Auth


OAuth account linking should be a deliberate action performed by a user who already controls the Own Auth account. A matching email is useful evidence only when the provider verified it and the application explicitly chose that policy. It is not a universal instruction to merge accounts.

Keep explicit linking as the default

Configure providers normally and leave account linking explicit. When a provider identity presents an email that already belongs to another Own Auth user, sign in returns account_linking_required. Ask the person to sign in through an existing method, then start a new OAuth transaction with the link intent.

auth.ts
import { createOwnAuth } from "own-auth";

export const auth = createOwnAuth({
  tokenPepper: process.env.OWN_AUTH_TOKEN_PEPPER!,
  redirectAllowlist: ["https://app.example.com"],
  oauth: {
    accountLinking: "explicit",
    providers: {
      google: {
        clientId: process.env.GOOGLE_CLIENT_ID!,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
        redirectUri: "https://api.example.com/api/auth/oauth/google/callback",
      },
    },
  },
});

Start linking from the signed in account

The browser client uses the current session cookie when it starts the link transaction. The callback verifies the provider response, consumes the single use transaction, and attaches the provider identity to that user. OAuth codes, provider tokens, and session tokens stay out of the destination URL.

account-security.ts
await authClient.signInWithOAuth({
  provider: "google",
  intent: "link",
  destination: "/account/security",
});

A provider identity already attached to another user returns oauth_account_conflict. Do not move it automatically. The user must recover the original account or complete a separately designed account merge process that verifies both accounts and resolves their application data.

Use verified email linking only by policy

Set accountLinking: "verified_email" only when every configured provider supplies an email whose verification semantics meet the application's account ownership requirements. Own Auth never uses an unverified email for linking. A provider subject remains the durable identity after the link, so later email changes do not break the account.

Automatic linking reduces one prompt but increases the consequence of a provider or email ownership mistake. Record the policy as a security decision, test each provider separately, and keep a recovery route that does not depend on the provider being removed.

Unlink one exact identity

List linked methods on a server generated account security screen. Unlinking requires the provider and its exact provider account identifier. The current Own Auth session identifies the actor. The HTTP handler does not accept an actor user ID from the browser.

unlink-provider.ts
await authClient.unlinkOAuthProvider({
  provider: "google",
  providerAccountId: selectedAccount.providerAccountId,
});

Own Auth rejects removal when it would leave the user without another usable authentication method. A password record, another linked provider, a passkey that can sign in, or another configured method must remain. The interface should explain which method will remain before asking for confirmation.

Treat provider access and account linking separately

Unlinking the Own Auth identity is not always the same as revoking offline provider access. If the application enabled encrypted provider refresh tokens, call auth.revokeExternalProviderAccess when the user disconnects that integration. Decide whether the product action should revoke provider access, unlink sign in, or perform both, then label it accurately.

Show the exact method being changed

An account security screen should show the provider name, the safe provider email when available, when the method was linked, and whether another sign in method remains. It should not expose raw provider subjects, provider tokens, or internal account hashes. When one user has two identities from the same provider, the interface must distinguish them before unlinking.

Require recent authentication before a sensitive unlink when losing the provider would materially change account recovery. The current session proves continuity, but a long lived unattended session may not provide enough assurance for security settings. The application decides that recent authentication policy and then calls the same Own Auth unlink method.

Recover without recreating the account

If a user removes a provider and later loses the remaining method, account recovery should restore access to the existing Own Auth user. Do not create a new user with the same email and attempt to merge product data afterward. Recovery needs independent verified evidence and should revoke existing sessions when account compromise is possible.

Audit the identity transition

Record the actor user ID, provider name, safe account reference, outcome, request time, and request context allowed by the audit policy. Do not record the authorization response, access token, refresh token, session token, or complete callback URL. Failed conflicts should use the same safe public error regardless of which user already owns the identity.

Test a new link, a repeated link, an email collision, an identity owned by another user, removal with another method present, and removal of the final method. Confirm that each successful change creates an audit event and that the next login resolves to the same Own Auth user ID. Never log callback parameters, provider access tokens, or raw session credentials while diagnosing these journeys.