- edited description
Consider JWT minting component
Nimbus has a robust component for processing a serialized JWT.
It would be nice to have a comparable component for minting a new JWT.
I’m thinking that the contract might look something like:
public String mint(JWSHeader header, JWTClaimsSet claimsSet, SecurityContext context)
The key would be retrieved from a JWKSource
using the JWSHeader
for selecting the JWK
. This could be overridden by setting a custom JWKSource
.
Having this action bundled together in a component makes it a bit easier for frameworks like Spring Security to expose configuration hooks.
Selecting the JWK
based on the provided header makes sense to me, though perhaps there are other ways that folks are doing it.
I’ll submit a PR that performs the above, though I wonder if an additional method (JWK, JWSHeader, JWTClaimSet, SecurityContext)
should be added. An application can achieve the same outcome by passing a JWKSecurityContext
and configuring with a JWKSecurityContextJWKSet
, but it feels a little cumbersome that way.
Comments (6)
-
reporter -
- changed status to open
Thanks Josh, this topic has not been given much attention yet. I mean, providing a general, universal and fairly robust mini framework for minting JWTs and general JOSE objects.
In 2020 Justin Richer contributed code to help with JWS minting, but that was for a rather specific case: https://www.javadoc.io/doc/com.nimbusds/nimbus-jose-jwt/latest/com/nimbusds/jose/produce/JWSSignerFactory.html
I'm currently reviewing some Connect2id server code and will use the opportunity to see if the suggested contract could work here. My strategy over the years has been to try to identify truly reusable code and patterns, and move them into the OIDC / OAuth SDK or here.
We'll also study the PR https://bitbucket.org/connect2id/nimbus-jose-jwt/pull-requests/73 that you submitted.
Thanks!
Vladimir
-
On first review, it looks like the proposed component is going to work here.
One bit that we found missing is the ability to configure the JWSMinter to include a X.509 certificate chain (x5c) in the JWS headers (when the signing key is selected).
Here is the complete list of key specific JWS headers:
- kid https://tools.ietf.org/html/rfc7515#section-4.1.4
- x5u https://tools.ietf.org/html/rfc7515#section-4.1.5 - used in Open Banking?
- x5c https://tools.ietf.org/html/rfc7515#section-4.1.6 - used often when the JWKs are part of a PKI
- x5t https://tools.ietf.org/html/rfc7515#section-4.1.7
- x5t#s256 https://tools.ietf.org/html/rfc7515#section-4.1.8
-
reporter Good point,
JWKMatcher#forJWSHeader
seems like a good place to enhance that. I can add that to my PR if you like, or would it be better to hammer that out elsewhere? -
Hi Josh,
I meant a config to determine what key specific JWS headers to set in
JWSHeader withJwk = new JWSHeader.Builder(header) .keyID(jwk.getKeyID()) .build();
after the JWS key is selected. The default impl in the PR sets the “kid”, but “x5c” and “x5u” can also come up. Covering all listed key specific headers would be ideal.
The JWK matching itself looks fine. The assumption (from reading the code) is that the client code needs to supply a minimal JWS header (setting the “alg” and perhaps “typ”) and let the minter fill in the key related headers.
I’m also curious if the use cases you’ve dealt with include some form of key rotation / key rollover. In the c2id server there is a convention to insert new JWKs at the top of the JWK set, so the proposed code will work for us. But there might be other conventions. My suggestion is to document this (for now) so that people are aware which key is going to get used if multiple match.
-
reporter Got it. I’ve updated the PR to add the
x5u
,x5c
,x5t
, andx5t#s256
headers. It pulls them from the JWK returned from the lookup, same as thekid
. The JavaDoc is updated, too.Also, I think it will be helpful for callers to be able to inspect the headers that were added without deserializing, so I changed the return type to
SignedJWT
. Callers would dominter.mint(headers, claims, null).serialize()
instead.Yes, supporting rotation is an important use case, and I think that selecting the first in the list is a reasonable default. I’ve added a test to demonstrate how that can be configured using the existing API. Personally, I’d prefer allowing for a custom
JWKSource
over introducing a new interface that returns a single JWK.I was thinking about use cases where the returned JWK doesn’t have any identifiers, e.g. no kid, etc. In that case, the signed JWT would have no hints for the recipient to know how to verify the signature. Since the spec only indicates that a JWS SHOULD have key identifying information in the header (as opposed to MUST), I’m inclined to leave it as is. If that sounds like an issue, though, maybe the implementation could throw an exception in that circumstance.
- Log in to comment