added config options and nonce
This commit is contained in:
parent
1613055dfd
commit
473d54569c
10 changed files with 146 additions and 85 deletions
74
jwt.go
74
jwt.go
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (C) 2018 Marius Schellenberger
|
||||
// Copyright (C) 2025 Marius Schellenberger
|
||||
|
||||
// Package jwt provides a easy to use JSON Web Token and blacklisting library
|
||||
package jwt
|
||||
|
|
@ -31,6 +31,8 @@ const (
|
|||
ExpClaim = "exp"
|
||||
// NbfClaim is the nbf claim name
|
||||
NbfClaim = "nbf"
|
||||
// NonceClaim
|
||||
NonceClaim = "nonce"
|
||||
// TokenSeparator is the tokens separator char
|
||||
TokenSeparator = "."
|
||||
)
|
||||
|
|
@ -57,14 +59,39 @@ var (
|
|||
ErrInvalidKeySize = errors.New(jwtErr + "invalid secret key size")
|
||||
)
|
||||
|
||||
type JWTOption func(*JWT)
|
||||
|
||||
func WithExpiry(expiry time.Duration) JWTOption {
|
||||
return func(jwt *JWT) {
|
||||
jwt.expiry = expiry
|
||||
}
|
||||
}
|
||||
|
||||
func WithBlacklist(blacklist Blacklist) JWTOption {
|
||||
return func(jwt *JWT) {
|
||||
jwt.blacklist = blacklist
|
||||
}
|
||||
}
|
||||
func WithSecret(secret io.Reader) JWTOption {
|
||||
return func(jwt *JWT) {
|
||||
jwt.secretReader = secret
|
||||
}
|
||||
}
|
||||
func WithNonce() JWTOption {
|
||||
return func(jwt *JWT) {
|
||||
jwt.nonce = true
|
||||
}
|
||||
}
|
||||
|
||||
// JWT represents the JSON Web Token signing and blacklisting infrastructure
|
||||
type JWT struct {
|
||||
key []byte
|
||||
expiry time.Duration
|
||||
|
||||
blacklist Blacklist
|
||||
stopOnce sync.Once
|
||||
done chan struct{}
|
||||
secretReader io.Reader
|
||||
key []byte
|
||||
expiry time.Duration
|
||||
blacklist Blacklist
|
||||
nonce bool
|
||||
stopOnce sync.Once
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// New returns a new JWT object with the given expiry timeout.
|
||||
|
|
@ -73,14 +100,18 @@ type JWT struct {
|
|||
// If secret is nil the DefaultSecretReader is used.
|
||||
// If blacklisting is enabled, the JWT object leaks a goroutine to garbage-collect expired blacklisted tokens.
|
||||
// Call the Stop() method to exit the goroutine.
|
||||
func New(expiry time.Duration, blacklist Blacklist, secret io.Reader) (*JWT, error) {
|
||||
if expiry <= 0 {
|
||||
expiry = DefaultExpiry
|
||||
func New(options ...JWTOption) (*JWT, error) {
|
||||
jwt := &JWT{}
|
||||
for _, option := range options {
|
||||
option(jwt)
|
||||
}
|
||||
if secret == nil {
|
||||
secret = DefaultSecretReader
|
||||
if jwt.expiry <= 0 {
|
||||
jwt.expiry = DefaultExpiry
|
||||
}
|
||||
secret = io.LimitReader(secret, KeySize)
|
||||
if jwt.secretReader == nil {
|
||||
jwt.secretReader = DefaultSecretReader
|
||||
}
|
||||
secret := io.LimitReader(jwt.secretReader, KeySize)
|
||||
key := make([]byte, KeySize)
|
||||
i, err := secret.Read(key)
|
||||
if err != nil {
|
||||
|
|
@ -89,12 +120,8 @@ func New(expiry time.Duration, blacklist Blacklist, secret io.Reader) (*JWT, err
|
|||
if i < KeySize {
|
||||
return nil, ErrInvalidKeySize
|
||||
}
|
||||
jwt := &JWT{
|
||||
key: key,
|
||||
expiry: expiry,
|
||||
blacklist: blacklist,
|
||||
}
|
||||
if blacklist != nil {
|
||||
jwt.key = key
|
||||
if jwt.blacklist != nil {
|
||||
jwt.done = make(chan struct{})
|
||||
go jwt.clean()
|
||||
}
|
||||
|
|
@ -128,7 +155,7 @@ func (jwt *JWT) Invalidate(t *Token) error {
|
|||
if t.Header.GetString(TypClaim) != Typ {
|
||||
return ErrNoJWT
|
||||
}
|
||||
h := ParseHash(t.Header.GetString(AlgClaim))
|
||||
h := NewHash(t.Header.GetString(AlgClaim))
|
||||
if h == nil {
|
||||
return ErrUnsupportedAlg
|
||||
}
|
||||
|
|
@ -190,7 +217,7 @@ func (jwt *JWT) Sign(t *Token) (err error) {
|
|||
if t.Header.GetString(TypClaim) != Typ {
|
||||
return ErrNoJWT
|
||||
}
|
||||
h := ParseHash(t.Header.GetString(AlgClaim))
|
||||
h := NewHash(t.Header.GetString(AlgClaim))
|
||||
if h == nil {
|
||||
return ErrUnsupportedAlg
|
||||
}
|
||||
|
|
@ -201,6 +228,9 @@ func (jwt *JWT) Sign(t *Token) (err error) {
|
|||
if _, ok := t.Claims.Get(NbfClaim); !ok {
|
||||
t.Claims.Set(NbfClaim, NewNbf(now))
|
||||
}
|
||||
if jwt.nonce {
|
||||
t.Claims.Set(NonceClaim, enc.EncodeToString(key16()))
|
||||
}
|
||||
head, err := json.Marshal(t.Header)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -230,7 +260,7 @@ func (jwt *JWT) Verify(t *Token) error {
|
|||
if t.Header.GetString(TypClaim) != Typ {
|
||||
return ErrNoJWT
|
||||
}
|
||||
h := ParseHash(t.Header.GetString(AlgClaim))
|
||||
h := NewHash(t.Header.GetString(AlgClaim))
|
||||
if h == nil {
|
||||
return ErrUnsupportedAlg
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue