Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

strategy:
matrix:
go-version: [1.20.x, 1.21.x, 1.22.x]
go-version: [1.22.x, 1.23.x, 1.24.x]
os: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion _example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import (

"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwt"
)

var tokenAuth *jwtauth.JWTAuth
Expand Down
15 changes: 6 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
module github.com/go-chi/jwtauth/v5

go 1.23.0

toolchain go1.24.2
go 1.24.3

require (
github.com/go-chi/chi/v5 v5.2.1
github.com/lestrrat-go/jwx/v2 v2.1.4
github.com/lestrrat-go/jwx/v3 v3.0.2
)

require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/blackmagic v1.0.3 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.6 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/httprc/v3 v3.0.0-beta2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/sys v0.33.0 // indirect
)
22 changes: 10 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs=
github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k=
github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.1.4 h1:uBCMmJX8oRZStmKuMMOFb0Yh9xmEMgNJLgjuKKt4/qc=
github.com/lestrrat-go/jwx/v2 v2.1.4/go.mod h1:nWRbDFR1ALG2Z6GJbBXzfQaYyvn751KuuyySN2yR6is=
github.com/lestrrat-go/httprc/v3 v3.0.0-beta2 h1:SDxjGoH7qj0nBXVrcrxX8eD94wEnjR+EEuqqmeqQYlY=
github.com/lestrrat-go/httprc/v3 v3.0.0-beta2/go.mod h1:Nwo81sMxE0DcvTB+rJyynNhv/DUu2yZErV7sscw9pHE=
github.com/lestrrat-go/jwx/v3 v3.0.2 h1:N+XLjTJEzDZRP3S0SezclXFAfopwL+o5vaL+qg6rX1I=
github.com/lestrrat-go/jwx/v3 v3.0.2/go.mod h1:qO9w1qkQH77a0r9OXNM33YQPnV/evetKYRg58h1rBNE=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -28,10 +26,10 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
22 changes: 10 additions & 12 deletions jwtauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (
"strings"
"time"

"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwa"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/lestrrat-go/jwx/v3/transform"
)

type JWTAuth struct {
Expand All @@ -34,8 +35,9 @@ var (
)

func New(alg string, signKey interface{}, verifyKey interface{}, validateOptions ...jwt.ValidateOption) *JWTAuth {
sigAlg, _ := jwa.LookupSignatureAlgorithm(alg)
ja := &JWTAuth{
alg: jwa.SignatureAlgorithm(alg),
alg: sigAlg,
signKey: signKey,
verifyKey: verifyKey,
validateOptions: validateOptions,
Expand Down Expand Up @@ -155,11 +157,11 @@ func (ja *JWTAuth) parse(payload []byte) (jwt.Token, error) {
// jwt library
func ErrorReason(err error) error {
switch {
case errors.Is(err, jwt.ErrTokenExpired()), err == ErrExpired:
case errors.Is(err, jwt.TokenExpiredError()), err == ErrExpired:
return ErrExpired
case errors.Is(err, jwt.ErrInvalidIssuedAt()), err == ErrIATInvalid:
case errors.Is(err, jwt.InvalidIssuedAtError()), err == ErrIATInvalid:
return ErrIATInvalid
case errors.Is(err, jwt.ErrTokenNotYetValid()), err == ErrNBFInvalid:
case errors.Is(err, jwt.TokenNotYetValidError()), err == ErrNBFInvalid:
return ErrNBFInvalid
default:
return ErrUnauthorized
Expand Down Expand Up @@ -202,15 +204,11 @@ func FromContext(ctx context.Context) (jwt.Token, map[string]interface{}, error)
token, _ := ctx.Value(TokenCtxKey).(jwt.Token)

var err error
var claims map[string]interface{}

claims := map[string]interface{}{}
if token != nil {
claims, err = token.AsMap(context.Background())
if err != nil {
if err = transform.AsMap(token, claims); err != nil {
return token, nil, err
}
} else {
claims = map[string]interface{}{}
}

err, _ = ctx.Value(ErrorCtxKey).(error)
Expand Down
51 changes: 26 additions & 25 deletions jwtauth_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//go:debug rsa1024min=0
package jwtauth_test

import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
Expand All @@ -15,8 +15,9 @@ import (

"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwa"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/lestrrat-go/jwx/v3/transform"
)

var (
Expand Down Expand Up @@ -44,7 +45,7 @@ DLxxa5/7QyH6y77nCRQyJ3x3UwF9rUD0RCsp4sNdX5kOQ9PUyHyOtCUCAwEAAQ==
)

func init() {
TokenAuthHS256 = jwtauth.New(jwa.HS256.String(), TokenSecret, nil, jwt.WithAcceptableSkew(30*time.Second))
TokenAuthHS256 = jwtauth.New(jwa.HS256().String(), TokenSecret, nil, jwt.WithAcceptableSkew(30*time.Second))
}

//
Expand Down Expand Up @@ -105,17 +106,17 @@ func TestSimpleRSA(t *testing.T) {

privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
if err != nil {
t.Fatalf(err.Error())
t.Fatal(err.Error())
}

publicKeyBlock, _ := pem.Decode([]byte(PublicKeyRS256String))

publicKey, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
t.Fatalf(err.Error())
t.Fatal(err.Error())
}

TokenAuthRS256 = jwtauth.New(jwa.RS256.String(), privateKey, publicKey)
TokenAuthRS256 = jwtauth.New(jwa.RS256().String(), privateKey, publicKey)

claims := map[string]interface{}{
"key": "val",
Expand All @@ -133,9 +134,9 @@ func TestSimpleRSA(t *testing.T) {
t.Fatalf("Failed to decode token string %s\n", err.Error())
}

tokenClaims, err := token.AsMap(context.Background())
if err != nil {
t.Fatal(err.Error())
tokenClaims := map[string]interface{}{}
if err := transform.AsMap(token, tokenClaims); err != nil {
t.Fatalf("Failed to get claims %s\n", err.Error())
}

if !reflect.DeepEqual(claims, tokenClaims) {
Expand All @@ -154,10 +155,10 @@ func TestSimpleRSAVerifyOnly(t *testing.T) {
publicKeyBlock, _ := pem.Decode([]byte(PublicKeyRS256String))
publicKey, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
t.Fatalf(err.Error())
t.Fatal(err.Error())
}

TokenAuthRS256 = jwtauth.New(jwa.RS256.String(), nil, publicKey)
TokenAuthRS256 = jwtauth.New(jwa.RS256().String(), nil, publicKey)

_, _, err = TokenAuthRS256.Encode(claims)
if err == nil {
Expand All @@ -169,9 +170,9 @@ func TestSimpleRSAVerifyOnly(t *testing.T) {
t.Fatalf("Failed to decode token string %s\n", err.Error())
}

tokenClaims, err := token.AsMap(context.Background())
if err != nil {
t.Fatal(err.Error())
tokenClaims := map[string]interface{}{}
if err := transform.AsMap(token, tokenClaims); err != nil {
t.Fatalf("Failed to get claims %s\n", err.Error())
}

if !reflect.DeepEqual(claims, tokenClaims) {
Expand Down Expand Up @@ -230,42 +231,42 @@ func TestMore(t *testing.T) {

// sending unauthorized requests
if status, resp := testRequest(t, ts, "GET", "/admin", nil, nil); status != 401 || resp != "token is unauthorized\n" {
t.Fatalf(resp)
t.Fatal(resp)
}

h := http.Header{}
h.Set("Authorization", "BEARER "+newJwtToken([]byte("wrong"), map[string]interface{}{}))
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "token is unauthorized\n" {
t.Fatalf(resp)
t.Fatal(resp)
}
h.Set("Authorization", "BEARER asdf")
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "token is unauthorized\n" {
t.Fatalf(resp)
t.Fatal(resp)
}
// wrong token secret and wrong alg
h.Set("Authorization", "BEARER "+newJwt512Token([]byte("wrong"), map[string]interface{}{}))
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "token is unauthorized\n" {
t.Fatalf(resp)
t.Fatal(resp)
}
// correct token secret but wrong alg
h.Set("Authorization", "BEARER "+newJwt512Token(TokenSecret, map[string]interface{}{}))
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "token is unauthorized\n" {
t.Fatalf(resp)
t.Fatal(resp)
}

h = newAuthHeader(map[string]interface{}{"exp": jwtauth.EpochNow() - 1000})
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "token is expired\n" {
t.Fatalf(resp)
t.Fatal(resp)
}

// sending authorized requests
if status, resp := testRequest(t, ts, "GET", "/", nil, nil); status != 200 || resp != "welcome" {
t.Fatalf(resp)
t.Fatal(resp)
}

h = newAuthHeader((map[string]interface{}{"user_id": 31337, "exp": jwtauth.ExpireIn(5 * time.Minute)}))
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 200 || resp != "protected, user:31337" {
t.Fatalf(resp)
t.Fatal(resp)
}
}

Expand Down Expand Up @@ -325,7 +326,7 @@ func newJwtToken(secret []byte, claims ...map[string]interface{}) string {
}
}

tokenPayload, err := jwt.Sign(token, jwt.WithKey(jwa.HS256, secret))
tokenPayload, err := jwt.Sign(token, jwt.WithKey(jwa.HS256(), secret))
if err != nil {
log.Fatal(err)
}
Expand All @@ -340,7 +341,7 @@ func newJwt512Token(secret []byte, claims ...map[string]interface{}) string {
token.Set(k, v)
}
}
tokenPayload, err := jwt.Sign(token, jwt.WithKey(jwa.HS512, secret))
tokenPayload, err := jwt.Sign(token, jwt.WithKey(jwa.HS512(), secret))
if err != nil {
log.Fatal(err)
}
Expand Down
Loading