Topics
Recent articles

Developer Tools

Why Uninstalling a Connector Does Not Revoke OAuth Access

Learn why removing a plugin or connector can leave OAuth authorization active, how to revoke it correctly, and how to verify the disconnect.

Table of Contents10 sections
Laptop displaying source code on a developer workspace
Disconnecting an integration is an authorization lifecycle problem, not merely an uninstall action.

You remove a connector, restart the application, and still see the service as connected. It feels like the uninstall failed. Often it did exactly what it was supposed to do.

The confusing part is that removing local integration code and revoking remote OAuth authorization are different operations. A plugin can disappear from your machine while the provider still has an authorization grant, refresh token, browser session, or cached connection record associated with the account.

The reliable fix is to identify which layer still considers the integration active, revoke the relevant authorization at the provider, clear local credentials when appropriate, then verify the connection with a fresh authenticated request.

The Four Layers Behind a “Connected” Integration

Most OAuth-backed integrations have more state than their user interface suggests.

A useful mental model is:

local integration
      |
      v
stored credentials
      |
      v
OAuth authorization grant
      |
      v
provider session / API access

Uninstalling usually affects the first layer. Depending on the application, it may also delete locally stored credentials. It does not automatically prove that the authorization server has invalidated the grant.

That separation is intentional. OAuth allows a resource owner to grant access to a client without making the client’s installation lifecycle the authority over the provider account.

This is similar to configuring an external tool through a portable MCP configuration: the local configuration describes how to reach a service, but the service still controls whether the presented credential is authorized.

Uninstall Is Not the Same as Revoke

Consider a desktop application that stores a refresh token after OAuth consent.

Removing the application can delete its executable and configuration files. But if the provider still recognizes the authorization grant, reinstalling the client or restoring its credential store may make the integration appear connected again.

OAuth 2.0 Token Revocation, standardized in RFC 7009, exists specifically so a client can tell an authorization server that a token is no longer needed. The specification requires support for revoking refresh tokens and recommends support for access-token revocation.

The important distinction is:

Action What it normally changes
Disable plugin Stops local code from running
Uninstall plugin Removes local integration files
Sign out Ends a local or provider session, depending on implementation
Delete cached credentials Removes the client’s local copy of tokens
Revoke OAuth authorization Invalidates authorization at the provider
Remove provider-side app access Removes the account’s authorization relationship

Those actions can overlap in a well-designed product, but you should not assume they do.

Start by Asking Who Says It Is Still Connected

Before deleting more files, determine where the “connected” signal comes from.

There are three common cases.

The local application still shows the integration

The application may be reading a cached connection record rather than testing the remote API.

Restart the application and inspect its integration settings. If it exposes a disconnect action, use that before manually deleting files because the action may also revoke remote credentials.

The provider still lists the application

This is the strongest sign that uninstalling locally did not remove the provider-side authorization.

For example, Cloudflare documents a Manage OAuth authorizations area where users can view authorized applications and revoke access. That operation lives with the provider because the provider owns the authorization grant.

Google similarly documents a revocation endpoint for OAuth access and refresh tokens.

API calls still succeed

This is the most useful technical test.

If an authenticated request succeeds using a credential you expected to be invalid, the credential or a related grant may still be active. Do not infer revocation from the UI alone.

A small verification probe is enough:

curl --fail-with-body \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://api.example.com/me

Use a harmless read-only endpoint. Never test disconnection by performing a destructive API operation.

Revoke at the Authorization Boundary

When you need a real disconnect, revoke access where authorization is controlled.

The exact mechanism depends on the provider. Common options are:

  1. a Disconnect or Revoke access button in the provider account;
  2. an OAuth token revocation endpoint;
  3. deletion of a provider-specific API token;
  4. removal of an application authorization or grant.

RFC 7009 defines an HTTPS revocation endpoint pattern. A simplified request looks like this:

curl -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "token=$REFRESH_TOKEN" \
  https://provider.example.com/oauth/revoke

Do not copy a generic endpoint into production. Use the provider’s documented revocation endpoint and authentication requirements.

Also pay attention to provider semantics. Revoking one access token does not universally mean every related credential is invalidated. RFC 7009 explicitly allows authorization servers to differ in how revocation affects related access tokens, refresh tokens, and grants.

Google’s documentation is a good example of why provider-specific behavior matters: its OAuth documentation describes revocation in terms of the scopes granted to a project and the tokens issued under that authorization.

Why a Connection Can Look Alive After Revocation

Even after a correct revoke operation, the interface may not update immediately.

Several caches can be involved:

provider authorization state
        |
        +--> API token validity
        |
        +--> application connection cache
        |
        +--> browser session
        |
        +--> background sync state

A stale UI does not prove that the token still works. Likewise, a missing UI badge does not prove that access has been revoked.

This is the same troubleshooting principle used in debugging broken deployment flows: verify each boundary independently instead of treating one visible symptom as proof of the whole pipeline.

After revocation, refresh the provider page, restart the client, and run a read-only API check with the old credential if doing so is safe. The expected result is an authentication or authorization failure.

A Safe Disconnect Checklist

Use this sequence when an integration refuses to disappear:

1. identify the integration and provider
2. disable background jobs that may refresh credentials
3. use the client's disconnect action if one exists
4. revoke provider-side OAuth authorization
5. remove local stored credentials
6. restart the client
7. verify the provider no longer lists the authorization
8. test the old credential against a harmless endpoint
9. reconnect only if a clean authorization is actually needed

The order matters. If a background process can still refresh credentials while you are cleaning up local state, it can make the integration appear to “come back.”

Do Not Delete Secrets Blindly

When troubleshooting authentication, random cleanup can make diagnosis harder.

Before removing credential files or environment variables, identify what they represent. A system may have separate credentials for development, CI, production, or multiple accounts. Deleting the wrong one can break an unrelated deployment without revoking the authorization you actually care about.

Prefer provider-side revocation first when the goal is security. Once the provider no longer accepts the credential, deleting local copies becomes cleanup rather than the primary control.

For CI systems, rotate or remove repository secrets only after confirming which workflow uses them. For desktop tools, check whether credentials live in a system keychain rather than a plain configuration file.

Build Integrations With a Real Disconnect Path

If you are building the integration rather than merely troubleshooting one, treat disconnect as part of the authentication lifecycle.

A robust implementation should:

Model the state explicitly:

sealed interface ConnectionState {
    data object Disconnected : ConnectionState
    data object Connecting : ConnectionState
    data object Connected : ConnectionState
    data object Revoking : ConnectionState
    data class Error(val reason: String) : ConnectionState
}

The application should not move to Disconnected merely because a local file was deleted. It should do so when its chosen disconnect contract has completed.

The Rule to Remember

When a connector still appears active after uninstalling it, do not immediately assume the uninstall mechanism is broken.

Ask which state survived.

Local installation, stored credentials, OAuth authorization, provider sessions, and cached connection metadata are separate layers. A clean disconnect means revoking access at the authorization boundary, cleaning local state, and verifying the result with evidence.

That model applies far beyond one provider. It is useful for IDE extensions, MCP connectors, CI integrations, cloud dashboards, desktop clients, and any other tool that delegates access through OAuth.

Continue Exploring

You Might Also Like

View all articles