A confidential client gets a client secret. A public client does not, and does not need one.
You see it once#
The secret is shown at creation, and once more if you rotate it. Only a hash of it is kept, so there is no way to read it back.
Where to keep it#
An environment variable read at startup, a secret manager, or a file the application user can read and nothing else can.
A repository, a container image layer, a client-side bundle, a log line, an error message, or a URL.
Rotating#
The new secret is shown once. The old one stops working immediately. There is no overlap window.
Rotating without downtime#
Since there is no overlap on one client, get the overlap from two:
Register a second application
Same redirect URIs, same permissions. It gets its own client id and secret.
Deploy it alongside the first
Your application accepts either, or you move traffic gradually.
Move everything to the new one
Existing sessions on the old client keep working until their refresh tokens are used.
Disable the old application
Rather than deleting it, which is not possible anyway. A disabled application refuses every flow.
For most applications a short maintenance window is simpler, and rotating in place is fine.
If one leaks#
Rotate immediately
Accept the downtime. A leaked secret is worse than a gap.
Disable the application if you cannot rotate at once
That stops every flow while you sort it out.
Revoke outstanding tokens
Rotating the secret does not revoke tokens already issued. Revoke the refresh tokens you know about.
Work out what the secret alone could do
On its own it cannot impersonate a user. It can complete a token exchange for an authorization code, which is why exact redirect URIs and PKCE matter even for confidential clients.
Public clients#
A public client has no secret at all. That is not a downgrade, it is an acknowledgement.
Anything in the bundle is readable. Register as public and use PKCE.
A binary can be inspected. Same answer.
PKCE is what replaces the secret. It proves that whoever redeems the authorization code is whoever started the flow, without any long-lived shared value.
Generating the verifier, and what happens without it.
Disabling#
A disabled application refuses every OAuth flow immediately. It does not on its own revoke tokens already issued, so pair it with revocation if that matters.
Archiving the project disables every application under it at once, and restoring re-enables exactly those.