Support verification of HS256-signed JWTs #134
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
When an OpenID provider such as Keycloak is configured to use the
HS256 algorithm to sign JSON Web Tokens (JWTs), previously logins
would fail with an obscure error:
The HS256 algorithm relies on a shared secret between the client and
the server, and this secret is not in the list of JSON Web Key Set
(JWKS) that is typically retrieved via a public endpoint during OpenID
Discovery.
The error was happening because decoding a HS256-signed JWT with
public key RSA key will fail. We should only attempt to decode with
the configured
client_options.secret
.To do this, we need to decode the JWT to examine the header to
determine how it was signed. For example:
This indicates that the payload was signed with
RS256
, a public keyalgorithm.
Once we know the algorithm used to decode, we can determine which key
to use. For public key algorithms such as
RS256
, we use theJWKS. For signature-based algoriths such as
HS256
, we use theconfigured client secret.
This merge request also cleans up some technical debt. Previously we
didn't peek at the unverified JWT to determine the key ID (
kid
) thatthe payload was signed with. If we got a
KidNotFound
exception fromthe decoding, previously we couldn't tell whether this was happening
because we didn't have a matching key in JWKS, or whether the JWT
didn't have a
kid
to begin with. Now that we decode the header, wecan tell these cases apart. If the JWT has no
kid
and we getKidNotFound
from decoding, we know the server didn't supply theright set of keys. Otherwise, we can just use try key until we find
one that works.
Relates to
https://gitlab.com/gitlab-org/ruby/gems/gitlab-omniauth-openid-connect/-/issues/1
This is part of the effort to upstream changes in the GitLab fork:
https://gitlab.com/gitlab-org/ruby/gems/gitlab-omniauth-openid-connect/-/issues/5.