Skip to content

Commit 751bf61

Browse files
committed
fix: suppress jwt code duplication and use internal jwt
1 parent 18d8af4 commit 751bf61

File tree

3 files changed

+48
-81
lines changed

3 files changed

+48
-81
lines changed

auth/strategies/jwt/jwt.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@ import (
1616
func GetAuthenticateFunc(s SecretsKeeper, opts ...auth.Option) token.AuthenticateFunc {
1717
t := newAccessToken(s, opts...)
1818
return func(ctx context.Context, r *http.Request, tk string) (auth.Info, time.Time, error) {
19-
c, err := t.parse(tk)
19+
c, info, err := t.parse(tk)
2020
if err != nil {
2121
return nil, time.Time{}, err
2222
}
2323

24-
if len(c.Scopes) > 0 {
25-
token.WithNamedScopes(c.UserInfo, c.Scopes...)
24+
if len(c.Scope) > 0 {
25+
token.WithNamedScopes(info, c.Scope.Split()...)
2626
}
27-
return c.UserInfo, c.Expiry.Time(), err
27+
28+
return info, time.Time(*c.ExpiresAt), nil
2829
}
2930
}
3031

auth/strategies/jwt/token.go

Lines changed: 37 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
package jwt
22

33
import (
4-
"errors"
4+
"fmt"
55
"time"
66

7-
"gopkg.in/square/go-jose.v2"
8-
"gopkg.in/square/go-jose.v2/jwt"
9-
107
"github.com/shaj13/go-guardian/v2/auth"
8+
"github.com/shaj13/go-guardian/v2/auth/claims"
9+
"github.com/shaj13/go-guardian/v2/auth/internal/jwt"
1110
)
1211

13-
const headerKID = "kid"
14-
1512
const (
1613
// EdDSA signature algorithm.
1714
EdDSA = "EdDSA"
@@ -29,11 +26,11 @@ const (
2926
RS512 = "RS512"
3027
// ES256 signature algorithm -- ECDSA using P-256 and SHA-256.
3128
ES256 = "ES256"
32-
// ES384 signature algorithm -- ECDSA using P-384 and SHA-384.
29+
// ES384 signature algorithm -- ECDSA using P-384 and SHA-384.
3330
ES384 = "ES384"
34-
// ES512 signature algorithm -- ECDSA using P-521 and SHA-512.
31+
// ES512 signature algorithm -- ECDSA using P-521 and SHA-512.
3532
ES512 = "ES512"
36-
// PS256 signature algorithm -- RSASSA-PSS using SHA256 and MGF1-SHA256.
33+
// PS256 signature algorithm -- RSASSA-PSS using SHA256 and MGF1-SHA256.
3734
PS256 = "PS256"
3835
// PS384 signature algorithm -- RSASSA-PSS using SHA384 and MGF1-SHA384.
3936
PS384 = "PS384"
@@ -44,24 +41,18 @@ const (
4441
var (
4542
// ErrMissingKID is returned by Authenticate Strategy method,
4643
// when failed to retrieve kid from token header.
47-
ErrMissingKID = errors.New("strategies/jwt: Token missing " + headerKID + " header")
44+
ErrMissingKID = jwt.ErrMissingKID
4845

4946
// ErrInvalidAlg is returned by Authenticate Strategy method,
5047
// when jwt token alg header does not match key algorithm.
51-
ErrInvalidAlg = errors.New("strategies/jwt: Invalid signing algorithm, token alg header does not match key algorithm")
48+
ErrInvalidAlg = jwt.ErrInvalidAlg
5249
)
5350

5451
// IssueAccessToken issue jwt access token for the provided user info.
5552
func IssueAccessToken(info auth.Info, s SecretsKeeper, opts ...auth.Option) (string, error) {
5653
return newAccessToken(s, opts...).issue(info)
5754
}
5855

59-
type claims struct {
60-
UserInfo auth.Info `json:"info"`
61-
Scopes []string `json:"scp"`
62-
jwt.Claims
63-
}
64-
6556
type accessToken struct {
6657
keeper SecretsKeeper
6758
dur time.Duration
@@ -71,76 +62,51 @@ type accessToken struct {
7162
}
7263

7364
func (at accessToken) issue(info auth.Info) (string, error) {
74-
kid := at.keeper.KID()
75-
secret, alg, err := at.keeper.Get(kid)
76-
if err != nil {
77-
return "", err
78-
}
79-
80-
opt := (&jose.SignerOptions{}).WithType("JWT").WithHeader(headerKID, kid)
81-
key := jose.SigningKey{Algorithm: jose.SignatureAlgorithm(alg), Key: secret}
82-
sig, err := jose.NewSigner(key, opt)
83-
84-
if err != nil {
85-
return "", err
86-
}
87-
88-
now := time.Now().UTC()
65+
now := time.Now().UTC().Add(-claims.DefaultLeeway)
8966
exp := now.Add(at.dur)
9067

91-
c := claims{
92-
UserInfo: info,
93-
Scopes: at.scp,
94-
Claims: jwt.Claims{
95-
Subject: info.GetID(),
96-
Issuer: at.iss,
97-
Audience: jwt.Audience{at.aud},
98-
Expiry: jwt.NewNumericDate(exp),
99-
IssuedAt: jwt.NewNumericDate(now),
100-
NotBefore: jwt.NewNumericDate(now),
101-
},
68+
c := claims.Standard{
69+
Subject: info.GetID(),
70+
Issuer: at.iss,
71+
Audience: claims.StringOrList{at.aud},
72+
ExpiresAt: (*claims.Time)(&exp),
73+
IssuedAt: (*claims.Time)(&now),
74+
NotBefore: (*claims.Time)(&now),
75+
Scope: at.scp,
10276
}
10377

104-
return jwt.Signed(sig).Claims(c).CompactSerialize()
105-
}
106-
107-
func (at accessToken) parse(tstr string) (*claims, error) {
108-
c := &claims{
109-
UserInfo: auth.NewUserInfo("", "", nil, nil),
110-
}
111-
112-
jt, err := jwt.ParseSigned(tstr)
78+
str, err := jwt.IssueToken(at.keeper, c, info)
11379
if err != nil {
114-
return nil, err
80+
return "", fmt.Errorf("strategies/jwt: %w", err)
11581
}
11682

117-
if len(jt.Headers) == 0 {
118-
return nil, errors.New("strategies/jwt: : No headers found in JWT token")
119-
}
83+
return str, nil
84+
}
12085

121-
if len(jt.Headers[0].KeyID) == 0 {
122-
return nil, ErrMissingKID
86+
func (at accessToken) parse(tstr string) (claims.Standard, auth.Info, error) {
87+
fail := func(err error) (claims.Standard, auth.Info, error) {
88+
return claims.Standard{}, nil, fmt.Errorf("strategies/jwt: %w", err)
12389
}
12490

125-
secret, alg, err := at.keeper.Get(jt.Headers[0].KeyID)
126-
127-
if err != nil {
128-
return nil, err
91+
info := auth.NewUserInfo("", "", nil, make(auth.Extensions))
92+
c := claims.Standard{}
93+
opts := claims.VerifyOptions{
94+
Audience: claims.StringOrList{at.aud},
95+
Issuer: at.iss,
96+
Time: func() (t time.Time) {
97+
return time.Now().UTC().Add(-claims.DefaultLeeway)
98+
},
12999
}
130100

131-
if jt.Headers[0].Algorithm != alg {
132-
return nil, ErrInvalidAlg
101+
if err := jwt.ParseToken(at.keeper, tstr, &c, info); err != nil {
102+
return fail(err)
133103
}
134104

135-
if err := jt.Claims(secret, c); err != nil {
136-
return nil, err
105+
if err := c.Verify(opts); err != nil {
106+
return fail(err)
137107
}
138108

139-
return c, c.Validate(jwt.Expected{
140-
Time: time.Now().UTC(),
141-
Issuer: at.iss,
142-
Audience: jwt.Audience{at.aud},
143-
})
109+
return c, info, nil
144110
}
145111

146112
func newAccessToken(s SecretsKeeper, opts ...auth.Option) *accessToken {

auth/strategies/jwt/token_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ func TestToken(t *testing.T) {
4242
str, err := tk.issue(info)
4343
assert.NoError(t, err)
4444

45-
c, err := tk.parse(str)
45+
_, u, err := tk.parse(str)
4646
assert.NoError(t, err)
47-
assert.Equal(t, c.UserInfo, info)
47+
assert.Equal(t, u, info)
4848
}
4949

5050
func TestTokenAlg(t *testing.T) {
@@ -68,15 +68,15 @@ func TestTokenAlg(t *testing.T) {
6868
assert.NoError(t, err)
6969

7070
tk.keeper = hs256
71-
_, err = tk.parse(str)
72-
assert.Equal(t, ErrInvalidAlg, err)
71+
_, _, err = tk.parse(str)
72+
assert.Contains(t, err.Error(), ErrInvalidAlg.Error())
7373
}
7474

7575
func TestTokenKID(t *testing.T) {
7676
str := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.P4Lqll22jQQJ1eMJikvNg5HKG-cKB0hUZA9BZFIG7Jk"
7777
tk := newAccessToken(nil)
78-
_, err := tk.parse(str)
79-
assert.Equal(t, ErrMissingKID, err)
78+
_, _, err := tk.parse(str)
79+
assert.Contains(t, err.Error(), ErrMissingKID.Error())
8080
}
8181

8282
func TestNewToken(t *testing.T) {

0 commit comments

Comments
 (0)