--- topic: the mesh status: accepted date: 2026-10-01 deciders: jochen reconstructed: false extends: 02-DECISIONS/0048-a-provider-creates-the-credential-the-mesh-minted.md --- # 158. A provider with one credential shares it with every consumer, and the vault remakes it for all of them at once ## Context [ADR 0048](0048-a-provider-creates-the-credential-the-mesh-minted.md) gave every consumer of a provision its own credential: the mesh mints one per pair, the provider's own code creates the login, and rotating one consumer's touches nothing else. That is right for a database, a broker, an object store — software that can hold many logins. The media software on the home server cannot. A download client has one web password; an indexer has one API key; each of the library managers has one key in its configuration; the media server holds one token issued elsewhere. There is no login per consumer to create, so [ADR 0113](0113-the-vault-makes-every-secret.md)'s only remaining form applied: the value is *accepted*. On 2026-10-01 the home server held forty-seven accepted own secrets and twelve accepted pair credentials, every one rotatable only by a person changing the software by hand and accepting the new value, and one pair credential sat *made* and wrong because nobody could accept the real one. The operator asked for every password in the vault and rotatable, and for a library manager's definition to receive the download client's credential and address through provisioning like anything else (filed as the forge's issue 243 on this repository). The address half already works: the library manager requires the download client's API provision, the provider serves scheme, port and user name, and the binding carries them. Only the credential half had no form. ## Considered Options 1. **Keep accepting.** Honest about what the software can do and what the mesh cannot, and it is the state the home server was in: nothing rotates, a consumer added later needs a person, and an unknown predecessor password stays unknown for ever. 2. **Put a login per consumer in front of the software.** A proxy that holds the one credential and issues many. A second service per provider, with its own credential to keep, to make the mesh's model fit software that does not share it. 3. **Let the provider say its one credential is the credential.** An offer names which of the provider's own secrets *is* what every consumer receives. The vault keeps one record, sealed to the provider's machine, every current consumer's machine and the operator, and because it stores no plaintext it cannot seal an existing value to a later consumer — so it **remakes the value for all of them at once** whenever the set of consumers changes or a rotation is asked. The provider takes it the way an own secret is taken ([ADR 0114](0114-a-shared-credential-rotates-over-two-credentials.md), issue 180); consumers read it at start. ## Decision **Option 3.** A provider whose software holds one credential shares that credential, and the mesh owns its whole lifecycle. - **The offer says so.** `{"name": "download-client-api", "credential": {"own": "password"}}` on a provider's `provides` entry names one of its own secrets as the credential of that provision. The named own secret must say how it is taken (`taken: at-start` or `taken: applied`); an offer naming an undeclared or untaken secret is refused at parse. - **One record, many seals.** The vault keeps one value per (provider assignment, provision). It is sealed to the provider's machine, to each consumer's machine that currently binds the provision, and to the operator. Every consumer's binding file carries the provider's one user name and the secret file carries the shared value; the shape a consumer reads is the pair credential's, so a consumer's definition does not know whether its credential is shared. - **Remade for all, together.** When a consumer binds or unbinds, or `secret rotate` is asked on the provider's own secret, the vault makes a new value and seals it to every current holder in one act, and the mesh sends every holding machine. The provider restarts on the new value or applies it at start; each consumer restarts on it. There is no window between two credentials, because there is one credential; there is the restart, stated as the cost below. - **An accepted shared value is sealed to everyone the moment it is accepted.** `secret accept` on the provider's own secret is the one moment the mesh holds the plaintext, and it seals copies for every current consumer then. It is not remade afterwards ([ADR 0113](0113-the-vault-makes-every-secret.md)): a consumer that binds later is refused until the value is accepted again, in words that say so. - **A value the software issues itself stays accepted.** A token the media server obtains from its vendor cannot be set by the mesh; its provision keeps the accepted form until a module can deliver a value it did not mint to the vault, which this record does not build. - **Nothing changes for software that holds many logins.** ADR 0048's form stays the default; this is the form for an offer that says it has one credential. ## Consequences - The media stack's six providers stop needing a person per consumer. A library manager binding the download client gets a working credential the mesh made, and an unknown predecessor password is replaced by one the mesh knows, recoverable with the operator's key. - **Adding or removing a consumer restarts every consumer of that provision and the provider.** That is the price of one credential, and it is paid when a definition binds, not at an hour of nobody's choosing. It is stated in the plan's words when it happens. - Rotation of a shared credential is [ADR 0114](0114-a-shared-credential-rotates-over-two-credentials.md)'s single-party form across several machines: in place, all holders sent together. The staged form for a backend that takes its credential once is still not built, and a provider whose own secret says `applied` refuses rotation by name until it is. - The vault can name who holds a shared value — the copies are the record — so *who has this* stays a query, as design 13 requires. - The accepted count on the home server becomes a list that shrinks, provider by provider, as each one's start applies the file. ## How this is checked | Rule | Checked by | |---|---| | An offer may name one of its own secrets as its credential; an undeclared or untaken secret is refused at parse | manifest tests | | A consumer of a shared provision receives the provider's value as its pair credential, under the provider's one user name | resolver and declaration tests | | The record is sealed to the provider, every current consumer and the operator; a consumer binding or unbinding remakes it for all | inventory tests against a raised store | | Rotating the provider's own secret remakes every holder's copy, and an accepted value is sealed to current consumers once and not remade | inventory tests | | Live: a library manager on the home server binds the download client with a value the mesh made, the client takes it at start, and a rotation through the console reaches both | done by hand after the media catalogue's providers apply the file at start | *2026-10-01:* the first four rows pass in mesh-controller PR 184 (`make check` green); the live row waits for the first provider definition to say `credential` and `taken`. ## References - [ADR 0048](0048-a-provider-creates-the-credential-the-mesh-minted.md) — extended: the per-consumer form stays the default; this is the form for one credential - [ADR 0113](0113-the-vault-makes-every-secret.md), [ADR 0114](0114-a-shared-credential-rotates-over-two-credentials.md) — the accepted form and the single-party rotation this rests on - [Issue 180](../04-ISSUES/180-a-modules-own-secret-cannot-be-rotated/00-report.md) — the `taken` word and the rotation this reuses - [Design 24 — The secrets vault](../03-DESIGN/01-to-be/24-the-secrets-vault.md), [Design 13 — Credentials and their rotation](../03-DESIGN/01-to-be/13-credentials-and-their-rotation.md) - The forge's issue 243 on this repository, where the operator's ask and the home server's count were recorded