The sole purpose of this package is to provide a
jwt.KeyFunc
for the
github.com/dgrijalva/jwt-go package using a JSON Web Key Set (JWKS) for parsing
JSON Web Tokens (JWTs).
It's common for an identity provider, such as Keycloak to expose a JWKS via an HTTPS
endpoint. This package has the ability to consume that JWKS and produce a
jwt.KeyFunc
. It is important that a JWKS
endpoint is using HTTPS to ensure the keys are from the correct trusted source.
There are no dependencies other than github.com/dgrijalva/jwt-go for this repository.
It is recommended to only use this package for asymmetric signing keys, If you are using HMAC signing keys, this Go package may be unnecessary as the algorithm is symmetric, meaning the key is pre-shared. In this case a JWKS is likely not be the best solution.
Currently, this package supports JWTs signed with an alg
that matches one of the following:
ES256
ES384
ES512
PS256
PS384
PS512
RS256
RS384
RS512
Additionally, the supported elliptical curve types are below:
P-256
P-384
P-521
If there are cryptographic algorithms, curve types, or something else already standardized that you'd like supported in this Go package, please open an issue or pull request.
Please also see the examples
directory.
import "github.com/chrisUsick/keyfunc"
A JWKS URL is not required, one can be created directly from JSON with the
keyfunc.New
function.
// Get the JWKS URL from an environment variable.
jwksURL := os.Getenv("JWKS_URL")
// Confirm the environment variable is not empty.
if jwksURL == "" {
log.Fatalln("JWKS_URL environment variable must be populated.")
}
// Create the JWKS from the resource at the given URL.
jwks, err := keyfunc.Get(jwksURL)
if err != nil {
log.Fatalf("Failed to get the JWKS from the given URL.\nError: %s", err.Error())
}
Additional options can be passed to the keyfunc.Get
function
via variadic arguments. See keyfunc.Options
.
Step 3: Use the keyfunc.JWKS
's JWKS.KeyFunc
method as the jwt.KeyFunc
when parsing tokens
// Parse the JWT.
token, err := jwt.Parse(jwtB64, jwks.KeyFunc)
if err != nil {
return nil, fmt.Errorf("failed to parse token: %w", err)
}
The JWKS.KeyFunc
method will automatically select
the key with the matching kid
(if present) and return its public key as the correct Go type to its caller.
Test coverage is currently at 84.3%
.
This is with current and expired JWTs, but the hard coded ones are now expired. Using non-expired JWTs would require signing JWTs during testing and would allow for additional error checking. But a bit overkill since I've already done that error checking when the JWTs were valid with no changes. A PR for this that does not introduce any dependencies is welcome though.
- A background refresh of the JWKS keys can be performed. This is possible by passing
keyfunc.Options
via a variadic argument to thekeyfunc.Get
function.- A custom background refresh interval can be specified.
- A custom background refresh request context timeout can be specified. Defaults to one minute.
- A custom background refresh error handling function can be specified. If none is specified, errors go unhandled silently.
- JWTs with a previously unseen
kid
can prompt an automatic refresh of the remote JWKS resource. - A custom HTTP client can be used. This is possible by passing
keyfunc.Options
via a variadic argument to thekeyfunc.Get
function.
- Add HMAC support?