Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2 release candidate #84

Merged
merged 10 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/MicahParks/keyfunc)](https://goreportcard.com/report/github.com/MicahParks/keyfunc) [![Go Reference](https://pkg.go.dev/badge/github.com/MicahParks/keyfunc.svg)](https://pkg.go.dev/github.com/MicahParks/keyfunc)
[![Go Report Card](https://goreportcard.com/badge/github.com/MicahParks/keyfunc/v2)](https://goreportcard.com/report/github.com/MicahParks/keyfunc/v2) [![Go Reference](https://pkg.go.dev/badge/github.com/MicahParks/keyfunc/v2.svg)](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2)

# keyfunc

The purpose of this package is to provide a
[`jwt.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#Keyfunc) for the
[github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) package using a JSON Web Key Set (JWK Set or JWKS) for
[`jwt.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#Keyfunc) for the
[github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) package using a JSON Web Key Set (JWK Set or JWKS) for
parsing and verifying JSON Web Tokens (JWTs).

The last version to support `github.com/golang-jwt/jwt/v4`
is [`v1.9.0`](https://github.com/MicahParks/keyfunc/releases/tag/v1.9.0).

There is legacy support for `github.com/dgrijalva/jwt-go` and its popular forks. It's in a separate project to keep this
project minimal. If your use case supports a legacy fork, please
see: [github.com/MicahParks/compatibility-keyfunc](https://github.com/MicahParks/compatibility-keyfunc).
see: [github.com/MicahParks/compatibility-keyfunc](https://github.com/MicahParks/compatibility-keyfunc). If an updated
to `keyfunc` is needed for `github.com/golang-jwt/jwt/v4` users, it will be placed into this separate project.

It's common for an identity provider, such as [Keycloak](https://www.keycloak.org/)
or [Amazon Cognito (AWS)](https://aws.amazon.com/cognito/) to expose a JWKS via an HTTPS endpoint. This package has the
ability to consume that JWKS and produce a
[`jwt.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#Keyfunc). It is important that a JWKS endpoint is using
[`jwt.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#Keyfunc). It is important that a JWKS endpoint is using
HTTPS to ensure the keys are from the correct trusted source.

This repository only depends on: [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt)
This repository only depends on: [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt)

`jwt.Keyfunc` signatures are imported from these, implemented, then exported as methods.

Expand Down Expand Up @@ -50,22 +54,22 @@ this Go package, please open an issue or pull request.
For complete examples, please see the `examples` directory.

```go
import "github.com/MicahParks/keyfunc"
import "github.com/MicahParks/keyfunc/v2"
```

#### A note on read-only keys

The [`JWKS.ReadOnlyKeys`](https://pkg.go.dev/github.com/MicahParks/keyfunc#JWKS.ReadOnlyKeys) method returns a read-only
The [`JWKS.ReadOnlyKeys`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#JWKS.ReadOnlyKeys) method returns a read-only
copy of a `map[string]interface{}`. The key to this map is the key ID, `kid`, and the value is the cryptographic key.
This is a useful map for use of keys within a JWKS outside of `github.com/golang-jwt/jwt/v4`.
This is a useful map for use of keys within a JWKS outside of `github.com/golang-jwt/jwt/v5`.

The map itself is a copy. So it can be modified safely. However, the values are of type `interface{}`. If these values
are modified, it may cause undefined behavior.

### Preconditions: Acquire the JWKS URL, JSON, or gather cryptographic keys (given keys)

A JWKS URL is not required, one can be created directly from JSON with the
[`keyfunc.NewJSON`](https://pkg.go.dev/github.com/MicahParks/keyfunc#NewJSON) function.
[`keyfunc.NewJSON`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#NewJSON) function.

```go
// Get the JWKS URL from an environment variable.
Expand Down Expand Up @@ -115,11 +119,11 @@ jwks := keyfunc.NewGiven(map[string]keyfunc.GivenKey{
})
```

Additional options can be passed to the [`keyfunc.Get`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4/keyfunc#Get)
function. See [`keyfunc.Options`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4/keyfunc#Options) and the additional
Additional options can be passed to the [`keyfunc.Get`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5/keyfunc#Get)
function. See [`keyfunc.Options`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5/keyfunc#Options) and the additional
features mentioned at the bottom of this `README.md`.

### Step 2: Use the [`JWKS.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4/keyfunc#JWKS.Keyfunc) method as the [`jwt.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#Keyfunc) when parsing tokens
### Step 2: Use the [`JWKS.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5/keyfunc#JWKS.Keyfunc) method as the [`jwt.Keyfunc`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#Keyfunc) when parsing tokens

```go
// Parse the JWT.
Expand All @@ -129,7 +133,7 @@ if err != nil {
}
```

The [`JWKS.Keyfunc`](https://pkg.go.dev/github.com/MicahParks/keyfunc#JWKS.Keyfunc) method will automatically select the
The [`JWKS.Keyfunc`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#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
Expand All @@ -143,8 +147,8 @@ coded JWTs cannot check for parsing and validation errors, just errors within th
## Additional features

These features can be configured by populating fields in the
[`keyfunc.Options`](https://pkg.go.dev/github.com/MicahParks/keyfunc#Options) argument to the
[`keyfunc.Get`](https://pkg.go.dev/github.com/MicahParks/keyfunc#Get) function.
[`keyfunc.Options`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#Options) argument to the
[`keyfunc.Get`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#Get) function.

* A background refresh of the JWKS keys can be performed.
* A custom background refresh interval can be specified. For an example, please see the `examples/interval`
Expand All @@ -164,10 +168,10 @@ These features can be configured by populating fields in the
* A custom HTTP response extractor can be provided to get the raw JWKS JSON from the `*http.Response`. For example, the
HTTP response code could be checked. Implementations are responsible for closing the response body.
* By default,
the [`keyfunc.ResponseExtractorStatusOK`](https://pkg.go.dev/github.com/MicahParks/keyfunc#ResponseExtractorStatusOK)
the [`keyfunc.ResponseExtractorStatusOK`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#ResponseExtractorStatusOK)
function is used. The default behavior changed in `v1.4.0`.
* A custom whitelist of acceptable JSON Web Key `"use"` parameter values can be specified. Values not whitelisted will
cause an error from the [`.Keyfunc`](https://pkg.go.dev/github.com/MicahParks/keyfunc#JWKS.Keyfunc) method. This
cause an error from the [`.Keyfunc`](https://pkg.go.dev/github.com/MicahParks/keyfunc/v2#JWKS.Keyfunc) method. This
whitelist can be disabled with the `JWKUseNoWhitelist` option.
* By default, only JSON Web Keys with a `"use"` parameter value of `"sig"`, an empty string `""`, or a completely
omitted `"use"` parameter will be returned. The default behavior changed in `v1.5.0`.
Expand All @@ -178,7 +182,7 @@ These features can be configured by populating fields in the
the `examples/given` directory.
* A copy of the latest raw JWKS `[]byte` can be returned.
* Custom cryptographic algorithms can be used. Make sure to
use [`jwt.RegisterSigningMethod`](https://pkg.go.dev/github.com/golang-jwt/jwt/v4#RegisterSigningMethod) before
use [`jwt.RegisterSigningMethod`](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#RegisterSigningMethod) before
parsing JWTs. For an example, see the `examples/custom` directory.
* The remote JWKS resource can be refreshed manually using the `.Refresh` method. This can bypass the rate limit, if the
option is set.
Expand Down
4 changes: 2 additions & 2 deletions alg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"errors"
"testing"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func TestAlgMismatch(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions checksum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"reflect"
"testing"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

// TestChecksum confirms that the JWKS will only perform a refresh if a new JWKS is read from the remote resource.
Expand Down
4 changes: 2 additions & 2 deletions ecdsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"errors"
"testing"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func TestBadCurve(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions examples/aws_cognito/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"log"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand Down
4 changes: 2 additions & 2 deletions examples/ctx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"log"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand Down
8 changes: 4 additions & 4 deletions examples/custom/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package main
import (
"log"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/examples/custom/method"
"github.com/MicahParks/keyfunc/v2"
"github.com/MicahParks/keyfunc/v2/examples/custom/method"
)

func main() {
Expand All @@ -29,7 +29,7 @@ func main() {

// Create the JWKS from the given signing method's key.
jwks := keyfunc.NewGiven(map[string]keyfunc.GivenKey{
exampleKID: keyfunc.NewGivenCustomWithOptions(key, keyfunc.GivenKeyOptions{
exampleKID: keyfunc.NewGivenCustom(key, keyfunc.GivenKeyOptions{
Algorithm: method.CustomAlgHeader,
}),
})
Expand Down
6 changes: 3 additions & 3 deletions examples/custom/method/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ const CustomAlgHeader = "customalg"
type EmptyCustom struct{}

// Verify helps implement the jwt.SigningMethod interface. It does not verify.
func (e EmptyCustom) Verify(_, _ string, _ interface{}) error {
func (e EmptyCustom) Verify(_ string, _ []byte, _ interface{}) error {
return nil
}

// Sign helps implement the jwt.SigningMethod interface. It does not sign anything.
func (e EmptyCustom) Sign(_ string, _ interface{}) (string, error) {
return CustomAlgHeader, nil
func (e EmptyCustom) Sign(_ string, _ interface{}) ([]byte, error) {
return []byte{}, nil
}

// Alg helps implement the jwt.SigningMethod. It returns the `alg` JSON attribute for JWTs signed with this method.
Expand Down
6 changes: 3 additions & 3 deletions examples/given/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"log"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand All @@ -23,7 +23,7 @@ func main() {
hmacSecret := []byte("example secret")
const givenKID = "givenKID"
givenKeys := map[string]keyfunc.GivenKey{
givenKID: keyfunc.NewGivenHMACCustomWithOptions(hmacSecret, keyfunc.GivenKeyOptions{
givenKID: keyfunc.NewGivenHMAC(hmacSecret, keyfunc.GivenKeyOptions{
Algorithm: jwt.SigningMethodHS256.Alg(),
}),
}
Expand Down
6 changes: 3 additions & 3 deletions examples/hmac/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package main
import (
"log"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand All @@ -23,7 +23,7 @@ func main() {

// Create the JWKS from the HMAC key.
jwks := keyfunc.NewGiven(map[string]keyfunc.GivenKey{
exampleKID: keyfunc.NewGivenHMACCustomWithOptions(key, keyfunc.GivenKeyOptions{
exampleKID: keyfunc.NewGivenHMAC(key, keyfunc.GivenKeyOptions{
Algorithm: jwt.SigningMethodHS512.Alg(),
}),
})
Expand Down
4 changes: 2 additions & 2 deletions examples/interval/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"log"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand Down
4 changes: 2 additions & 2 deletions examples/json/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"encoding/json"
"log"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand Down
4 changes: 2 additions & 2 deletions examples/keycloak/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"log"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand Down
4 changes: 2 additions & 2 deletions examples/recommended_options/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"log"
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"
"time"

"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
)

func TestJWKS_Refresh(t *testing.T) {
Expand Down
Loading