Topolo Docs Topolo Platform
Open workspace

Unlink user OAuth provider

Remove one Auth provider link after separately verifying alternate sign-in; external accounts and sessions are unchanged.

Outcome

Remove one Auth provider link after separately verifying alternate sign-in; external accounts and sessions are unchanged.

These examples prove local handler behavior with real isolated SQL and explicitly simulated identity/permission dependencies.

Before you start

  • Verify the intended authenticated identity and the current credential-scoped action before preparing input. Self and managed-user security operations have different authority; a session id does not authorize a different user.

  • Use authorized identity and user/session discovery. Recovery security data and session/device identifiers must remain inside the caller-approved workflow.

  • Review the validated plan and intended effect before confirmation. Provider unlink can remove the last linked provider; verify an alternate working sign-in method first. Unlock clears a lockout, not password, MFA or suspended status. Fixture examples authorize no live mutation or external delivery.

Discover the target

topolo whoami --json
topolo apps --json
topolo actions get app_topolo_auth.user_oauth_providers.unlink --detail --json

Use the caller subject or a user returned by authorized users discovery. Read user_oauth_providers.list for that exact user before unlinking a returned provider name; providerUserId is an external identity. Unlock requires target-user management authority.

Input fields

FieldRequiredMeaning
userIdYesExisting Auth user id from authorized identity or user discovery. Provider links allow self or authorized managed-user access; account unlock requires target-user management authority even for a self request.
providerYesCanonical linked provider name copied from user_oauth_providers.list, such as github. The handler trims and lowercases it, then deletes only that user/provider pair. Verify an alternate working sign-in method before approving unlink; the action does not prevent removal of the sole linked provider.

Effects

  • Deletes exactly one selected user/provider link in Auth; no provider-side account/token/consent revocation is performed.

  • Does not guard against removing the sole provider. Audit persistence is nonfatal and existing Auth sessions are unchanged.

Interpret the response

HTTP 200 successes use raw target success/message/data/timestamp, which CLI/MCP can wrap or project. Record times are epoch seconds; the envelope timestamp is ISO text. Local fixtures use real canonical SQL and target-user authority with simulated token identity and user organization lookup. They prove neither live permissions nor actual sign-in.

The normalized user/provider pair is deleted from local Auth links. data.provider and removed acknowledge that deletion. Repeating the unlink returns NOT_FOUND. The implementation permits deleting the sole provider and does not verify another sign-in method; establish an alternate usable route before confirming the action.

This removes the Auth account association, not the external account, external-provider token grants, OAuth consent, existing Auth sessions, API keys or service credentials. Those effects need separately authorized operations. Nonfatal audit failure can follow deletion without changing the successful response. Other users links remain separate.

Self access accepts the subject or userId identity alias; managed-user access requires current target-user authority. Bearer takes precedence over access cookies. Missing identity/link is NOT_FOUND, foreign-user authority is FORBIDDEN and invalid token exceptions currently become SERVER_ERROR.

Worked examples

These are complete raw target-handler responses, not CLI/gateway envelopes or live authorization proof. Replace synthetic identifiers using authorized discovery. Save only the reviewed input as payload.json; inspect validation and plan before executing. --confirm assumes the intended operation is approved. Storage read-back and actual sign-in outcomes require separate verification. Provider unlink does not revoke external accounts, consent or existing Auth sessions. Cookies and Bearer tokens must identify the intended principal consistently.

Input · payload.json:

{
  "userId": "usr_self",
  "provider": "GitHub"
}

CLI:

topolo actions validate app_topolo_auth.user_oauth_providers.unlink --data @payload.json --json
topolo actions plan app_topolo_auth.user_oauth_providers.unlink --data @payload.json --confirm --json
topolo actions call app_topolo_auth.user_oauth_providers.unlink --data @payload.json --confirm --json

MCP call after validation and plan review:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.user_oauth_providers.unlink",
    "input": {
      "userId": "usr_self",
      "provider": "GitHub"
    },
    "confirm": true
  }
}

Captured local handler response · HTTP 200:

{
  "success": true,
  "message": "OAuth provider unlinked",
  "data": {
    "provider": "github",
    "removed": true
  },
  "timestamp": "2026-10-02T00:00:00.000Z"
}

Input · payload.json:

{
  "userId": "usr_managed",
  "provider": "github"
}

CLI:

topolo actions validate app_topolo_auth.user_oauth_providers.unlink --data @payload.json --json
topolo actions plan app_topolo_auth.user_oauth_providers.unlink --data @payload.json --confirm --json
topolo actions call app_topolo_auth.user_oauth_providers.unlink --data @payload.json --confirm --json

MCP call after validation and plan review:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_auth.user_oauth_providers.unlink",
    "input": {
      "userId": "usr_managed",
      "provider": "github"
    },
    "confirm": true
  }
}

Captured local handler response · HTTP 200:

{
  "success": true,
  "message": "OAuth provider unlinked",
  "data": {
    "provider": "github",
    "removed": true
  },
  "timestamp": "2026-10-02T00:00:00.000Z"
}

Verify the result

  • List providers for the exact same Topolo user and require the normalized provider to be absent while unrelated links remain. Repeating unlink returns NOT_FOUND.

  • Confirm the alternate intended sign-in method still works as this user. Verify external consent/token revocation separately only if that was independently requested and authorized.

Errors and recovery

Captured local refusal · HTTP 404:

{
  "input": {
    "userId": "usr_self",
    "provider": "github"
  },
  "response": {
    "success": false,
    "error": {
      "message": "OAuth provider link not found",
      "code": "NOT_FOUND",
      "details": null,
      "timestamp": "2026-10-02T00:00:00.000Z"
    }
  }
}

Captured local refusal · HTTP 403:

{
  "input": {
    "userId": "usr_foreign",
    "provider": "github"
  },
  "response": {
    "success": false,
    "error": {
      "message": "Insufficient permissions",
      "code": "FORBIDDEN",
      "details": null,
      "timestamp": "2026-10-02T00:00:00.000Z"
    }
  }
}

Captured local refusal · HTTP 404:

{
  "input": {
    "userId": "usr_missing",
    "provider": "github"
  },
  "response": {
    "success": false,
    "error": {
      "message": "User not found",
      "code": "NOT_FOUND",
      "details": null,
      "timestamp": "2026-10-02T00:00:00.000Z"
    }
  }
}

Captured local refusal · HTTP 401:

{
  "input": {
    "userId": "usr_self",
    "provider": "google"
  },
  "response": {
    "success": false,
    "error": {
      "message": "Access token required",
      "code": "AUTH_ERROR",
      "details": null,
      "timestamp": "2026-10-02T00:00:00.000Z"
    }
  }
}

Published recovery guidance

  • state_conflict (HTTP 409): Read the current resource state, reconcile the intended change, and retry only if still valid.

  • AUTH_ERROR (HTTP 401): Verify the intended identity and transport. Unlock AUTH_ERROR can mean authenticated target-user authority denial; refresh only a genuinely expired token for the approved context.

  • FORBIDDEN (HTTP 403): Preserve the target-user authority denial. Use only an approved identity authorized for this exact user/organization; do not switch contexts automatically.

  • NOT_FOUND (HTTP 404): Refresh authorized user/provider discovery. Repeated unlink reports a missing link; do not create a fictitious link or infer external account deletion.

  • SERVER_ERROR (HTTP 500): Preserve the original error, verify the approved authentication and inspect current target state before reviewing any retry. Invalid-token exceptions and repository errors are both possible.

Recovery boundaries

No direct provider relink action is published in this family. The user must complete the normal approved provider authentication/linking journey if restoration is intended. Preserve prior provider/user identity and alternate sign-in proof; do not fabricate a link or restore a copied external token. After an unknown response read current links before reviewing a retry.

Discovery and evidence

This record belongs to app_topolo_auth. Local tests prove real canonical provider/security SQL, target-user authorization and handler responses with simulated tokens and identity lookup. They do not prove live permission, alternate sign-in, external-provider token/consent revocation, actual user login, deployment or production completion.