---
id: STATE-PFM-INT-004
title: Credential lifecycle
object: DOM-PFM-INT-002
product_area: platform
module: integrations
revision: 1
status: draft
design_intent: confirmed
implementation_evidence: observed
origin: docs/milestones/INTG-M1-find-install-connect.md#Decisions D5 (INTG-M1 Product Accepted)
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
  - name: active
    meaning: This credential is selected for current account use.
  - name: superseded
    meaning: A replacement is current and this secret is scheduled for recoverable deletion.
  - name: revoked
    meaning: The account ended and this secret is awaiting deletion.
  - name: destroyed
    meaning: 'Storage no longer contains the secret, while its record preserves history.'
transitions:
  - from: active
    to: superseded
    trigger: Supply a replacement credential
    guard: The store commits a new credential for this account
    side_effects:
      - Request old-secret deletion with seven days of recovery
      - Submit verification unless the account is paused.
    who: Credential store
    provenance: observed
    source: 'services-platform:modules/integrations/services/credentials/credential-passes.ts'
  - from: active
    to: revoked
    trigger: End the provider account link
    guard: Disconnection or discard revokes its credential
    side_effects:
      - Request secret deletion.
    who: Credential hook on disconnection
    provenance: observed
    source: 'services-platform:modules/integrations/services/persistence/integration-credentials.ts'
  - from: superseded
    to: destroyed
    trigger: Observe deletion of a replaced secret
    guard: Secret storage reports that the value is absent
    side_effects:
      - Save destroyed status.
    who: Daily credential maintenance
    provenance: observed
    source: 'services-platform:modules/integrations/services/credentials/credential-passes.ts'
  - from: revoked
    to: destroyed
    trigger: Observe deletion of a revoked secret
    guard: Secret storage reports that the value is absent
    side_effects:
      - Save destroyed status.
    who: Daily credential maintenance
    provenance: observed
    source: 'services-platform:modules/integrations/services/credentials/credential-passes.ts'
invalid:
  - from: destroyed
    to: active
    why: A destroyed value cannot supply authentication again.
  - from: superseded
    to: active
    why: The old record is not restored; supplying credentials creates another record.
concurrency: >-
  Secret creation precedes the database credential transaction. A refused database change requests cleanup of
  the new secret, while successful replacement requests recoverable deletion of the old one. Refresh locking
  serializes token requests per account.
invariants:
  - INV-DOM-PFM-INT-002-05
  - INV-DOM-PFM-INT-002-06
  - INV-DOM-PFM-INT-002-07
evidence:
  - >-
    services-platform at ad3f6a65: modules/integrations/db/integration-credentials.table.ts;
    services/credentials/credential-store.ts, broker.ts, credential-passes.ts; docs/integrations/README.md
    (Credentials)
---

# Credential lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  state "active" as s0
  state "superseded" as s1
  state "revoked" as s2
  state "destroyed" as s3
  s0 --> s1: Supply a replacement credential
  s0 --> s2: End the provider account link
  s1 --> s3: Observe deletion of a replaced secret
  s2 --> s3: Observe deletion of a revoked secret
```

## Transitions Explained

Supplying authentication creates a fresh credential and replaces the current one. Disconnection revokes the selected credential. Maintenance records destruction only after storage no longer contains the value, so deletion scheduling and database state can temporarily differ.

## What Cannot Happen

A destroyed value cannot supply authentication again. The old record is not restored; supplying credentials creates another record.

## Concurrency and Timing

Secret creation precedes the database credential transaction. A refused database change requests cleanup of the new secret, while successful replacement requests recoverable deletion of the old one. Refresh locking serializes token requests per account.
