Skip to content

A revoked subscription disappears from the Providers page with no explanation #510

Description

@czpython

Problem

When a refresh grant fails with invalid_grant, rotate_token revokes the subscription. The comment on that path says "the UI shows Reconnect" — but the UI cannot show it: VaultSecret._list filters revoked_at IS NULL, so GET /api/providers/subscriptions omits the revoked row and the Providers page renders no card for that provider at all.

The result is indistinguishable from never having connected the provider. The Usage page says only "not connected". The reason (revoked_reason), the time (revoked_at), and the account identity sit unread in the vault table. The operator's first theory is a druks bug, and the diagnosis needs a database query.

Observed: the nightly refresh tick presented a refresh token, the provider answered invalid_grant, the row was revoked at 03:30 — correct behavior. The next morning the provider card was simply gone, with agents on that subscription failing at seat resolution.

Proposal

Surface the revocation instead of hiding the row. The data is already persisted: revoke() keeps revoked_at, revoked_reason, and identity, and wipes only the secrets.

  1. list_subscriptions also returns the latest revoked row per provider and account — as a status: connected | revoked field rather than omission.
  2. The card renders it: "Disconnected — the provider rejected the stored credential (invalid_grant) on . Reconnect to restore." with the Reconnect button.
  3. A fresh connect supersedes the revoked row, as it already does.

The revocation behavior itself stays as is — dropping the dead lineage so the next tick has no row to hammer is right.

Related gap: no rotation history

Post-mortem on a dead grant is nearly blind today. created_at is stamped by whatever wrote the row (a refresh persist or a migration, not necessarily the operator's connect), and revoke() is the last write, so updated_at no longer shows the last successful refresh. Consider stamping the last successful rotation separately (one timestamp column or an identity field), so the surfaced card can say when the credential last worked.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions