Let the issuer generate a client's secret¶
Stop delivering a confidential client's secret by hand. The issuer makes it, keeps it and exposes it to the relying party.
Before you start¶
-
Use a confidential client (
kind: confidential), a Secrets adapter that writes only if absent (ssmoropenbao), and a State shared between replicas such asdynamodb. Start is refused otherwise. -
If
clients/<id>/secretexists when the issuer first looks, it is adopted unchanged and nothing rotates.
1. Declare the client as generated¶
clients:
grafana:
kind: confidential
secret: {generate: true} # was: secret: grafana-oidc
pkce: required # when the relying party sends an S256 challenge
requires: [devel:grafana:viewer]
redirects: [/login/generic_oauth]
The issuer creates credentials/oidc-client/grafana/secret. The audit trail shows roster.client.secret.adopted when an input existed, else roster.client.secret.created.
sluisctl clients show grafana
It prints created and generated in policy true.
2. Point the relying party at the document¶
The secret lives once, as the oidc/v1 document at external/oidc/<client> (secrets). Grant the relying party that address on its own side. For External Secrets, set the ExternalSecret's remoteRef.key to external/oidc/<client> under the installation's root and property to client-secret. The issuer never touches the relying party's Secret.
The document holds only the current secret. Verify: a sign-in to the relying party succeeds.
3. Remove the input secret¶
Delete clients/<id>/secret from wherever the installation delivers inputs. The token endpoint ignores the input once the stored record exists. sluisctl clients show <id> still shows the record.
Roll back¶
Put the name back in secret. The stored record is then reported as orphaned and kept (rotate a client secret). Rotated-away values stay in the store's version history, readable by whoever can read the store.
A failure for one client is logged and counted as sluis.client_secret.reconcile. It is retried every five minutes on a server and on the directory refresh on Lambda.
Decided in¶
ADR 0039. Fields: secret in the policy. Rotate with rotate a client secret.