HOG v2.2.0¶
A minor release: one new field on the IdP resource, verificationOnly, for
a deployment that runs one instance for login and another for verification.
Nothing existing changes.
An IdP that only verifies tokens¶
HOG's IdP resource has always described a full OpenID Connect relying
party, and refused to build without all four of issuer, clientID,
clientSecret and redirectURL. That is right for the instance that logs
users in. It is wrong for an instance that never does.
Consider a deployment split across two HOG instances. The first terminates
the OIDC session: it runs the authorization-code flow, holds the cookie, and
refreshes the access token. The second sits in front of the APIs and only
ever verifies a Bearer access token the first obtained; it declares no
session, so it mounts no login, logout or callback route and never performs
a code exchange. Both need an IdP — verification is a protocol operation,
and discovery is what resolves the key set the token is checked against — but
only the first needs to be able to start a login flow.
Until now the second one had to be handed a client secret it could never use and a redirect URL naming a route it does not serve. That is not merely untidy: it copies a credential into a second workload and a second secret store for no functional reason, and the verifying instance is typically the one exposed to all of the platform's API traffic. Every extra copy of a secret is another place it can leak.
An IdP can now say what it is for:
kind: IdP
metadata: { name: corp-oidc }
spec:
type: oidc
verificationOnly: true # verifies tokens; never starts a login flow
issuer: https://idp.example.com # discovery finds the key set; every token is checked against it
clientID: ${OIDC_CLIENT_ID} # the expected audience
That is the whole resource. verificationOnly requires the two fields
verification genuinely uses and drops the two it does not.
clientSecret and redirectURL are rejected on such an IdP rather than
ignored, so a configuration copied from the login instance and left unedited
fails at startup instead of quietly carrying a credential that instance can
never spend.
Everything on the verification side is unchanged: bearerAudience, the
bearer: block, identity.subjectClaim, group derivation, route
access/authorize, and both directions of the identity assertion all work
exactly as they do on a full instance. Only the login flow is absent.
It is always explicit¶
HOG does not infer verification-only from the absence of a session block.
Inferring it would mean that adding a session to an existing configuration
silently changed what its IdP resource had meant — and a configuration file
should not change meaning because a different file grew a new block. The
declaration is a field an operator writes, or does not.
What is refused, and why¶
A verification-only IdP holds no client secret and no redirect URL, so it
cannot run the authorization-code flow — and the callback of that flow is the
only thing in HOG that issues a session cookie. A gateway that configures
both a session and a verification-only IdP therefore describes a login that
can never happen: no login, callback or logout endpoint would be mounted, and
every protected app route would redirect to a path that answers 404. That
combination is refused when the gateway is built, with an error that names
both halves and the two ways out of it.
A lone auth block (loginPath, logoutPath) is not part of that check.
Without a session it is inert for every configuration, verification-only or
not, so it says nothing contradictory on its own.
Below the configuration layer, the connector itself refuses to start a login
flow out loud rather than quietly producing a broken one: Exchange and
Refresh return an error naming the field, and AuthCodeURL — which has no
error to return — panics rather than hand back an authorization URL with an
empty redirect_uri. A configured gateway never reaches those; they catch
the framework-mode caller that wires the auth handlers by hand.
Upgrade notes¶
Nothing to change. An IdP that does not set verificationOnly keeps
exactly the behaviour, and exactly the strictness, it has today: all four of
issuer, clientID, clientSecret and redirectURL remain required.
If you run a verifying instance that was given a client secret only to
satisfy that requirement, you can now delete the secret from its
configuration — and from whatever secret store fed it — and add
verificationOnly: true:
kind: IdP
metadata: { name: corp-oidc }
spec:
type: oidc
verificationOnly: true
issuer: https://idp.example.com
clientID: ${OIDC_CLIENT_ID}
# clientSecret and redirectURL: removed, and now rejected if present
See authentication: an instance that only verifies tokens, deployment topology and security hardening.