Skip to content

Commit f864f62

Browse files
committedNov 5, 2019
improve builder
1 parent 35633bc commit f864f62

File tree

2 files changed

+136
-49
lines changed

2 files changed

+136
-49
lines changed
 

‎build.go

+68-49
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package jwt
22

33
import (
4-
"encoding"
54
"encoding/base64"
65
"encoding/json"
76
)
@@ -19,16 +18,26 @@ type TokenBuilder struct {
1918
header Header
2019
}
2120

21+
// BinaryMarshaler a marshaling interface for user claims.
22+
type BinaryMarshaler interface {
23+
MarshalBinary() (data []byte, err error)
24+
}
25+
26+
// BuildBytes is used to create and encode JWT with a provided claims.
27+
func BuildBytes(signer Signer, claims BinaryMarshaler) ([]byte, error) {
28+
return NewTokenBuilder(signer).BuildBytes(claims)
29+
}
30+
2231
// Build is used to create and encode JWT with a provided claims.
23-
func Build(signer Signer, claims encoding.BinaryMarshaler) (*Token, error) {
32+
func Build(signer Signer, claims BinaryMarshaler) (*Token, error) {
2433
return NewTokenBuilder(signer).Build(claims)
2534
}
2635

2736
// BuildWithHeader is used to create and encode JWT with a provided claims.
28-
func BuildWithHeader(signer Signer, header *Header, claims encoding.BinaryMarshaler) (*Token, error) {
37+
func BuildWithHeader(signer Signer, header Header, claims BinaryMarshaler) (*Token, error) {
2938
b := &TokenBuilder{
3039
signer: signer,
31-
header: *header,
40+
header: header,
3241
}
3342
return b.Build(claims)
3443
}
@@ -46,18 +55,26 @@ func NewTokenBuilder(signer Signer) *TokenBuilder {
4655
return b
4756
}
4857

49-
// Build used to create and encode JWT with a provided claims.
50-
func (b *TokenBuilder) Build(claims encoding.BinaryMarshaler) (*Token, error) {
51-
encodedHeader := b.encodeHeader()
58+
// BuildBytes used to create and encode JWT with a provided claims.
59+
func (b *TokenBuilder) BuildBytes(claims BinaryMarshaler) ([]byte, error) {
60+
token, err := b.Build(claims)
61+
if err != nil {
62+
return nil, err
63+
}
64+
return token.Raw(), nil
65+
}
5266

67+
// Build used to create and encode JWT with a provided claims.
68+
func (b *TokenBuilder) Build(claims BinaryMarshaler) (*Token, error) {
5369
rawClaims, encodedClaims, err := encodeClaims(claims)
5470
if err != nil {
5571
return nil, err
5672
}
5773

74+
encodedHeader := encodeHeader(&b.header)
5875
payload := concatParts(encodedHeader, encodedClaims)
5976

60-
signed, signature, err := b.signPayload(payload)
77+
signed, signature, err := signPayload(b.signer, payload)
6178
if err != nil {
6279
return nil, err
6380
}
@@ -72,55 +89,57 @@ func (b *TokenBuilder) Build(claims encoding.BinaryMarshaler) (*Token, error) {
7289
return token, nil
7390
}
7491

75-
func (b *TokenBuilder) encodeHeader() []byte {
76-
switch b.signer.Algorithm() {
77-
case NoEncryption:
78-
return []byte("eyJhbGciOiJub25lIn0")
79-
case EdDSA:
80-
return []byte("eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9")
81-
82-
case HS256:
83-
return []byte("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
84-
case HS384:
85-
return []byte("eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9")
86-
case HS512:
87-
return []byte("eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9")
88-
89-
case RS256:
90-
return []byte("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9")
91-
case RS384:
92-
return []byte("eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9")
93-
case RS512:
94-
return []byte("eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9")
95-
96-
case ES256:
97-
return []byte("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9")
98-
case ES384:
99-
return []byte("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9")
100-
case ES512:
101-
return []byte("eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9")
102-
103-
case PS256:
104-
return []byte("eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9")
105-
case PS384:
106-
return []byte("eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9")
107-
case PS512:
108-
return []byte("eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9")
109-
110-
default:
111-
// another algorithm? encode below
92+
func encodeHeader(header *Header) []byte {
93+
if header.Type == "JWT" {
94+
switch header.Algorithm {
95+
case NoEncryption:
96+
return []byte("eyJhbGciOiJub25lIn0")
97+
case EdDSA:
98+
return []byte("eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9")
99+
100+
case HS256:
101+
return []byte("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
102+
case HS384:
103+
return []byte("eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9")
104+
case HS512:
105+
return []byte("eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9")
106+
107+
case RS256:
108+
return []byte("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9")
109+
case RS384:
110+
return []byte("eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9")
111+
case RS512:
112+
return []byte("eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9")
113+
114+
case ES256:
115+
return []byte("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9")
116+
case ES384:
117+
return []byte("eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9")
118+
case ES512:
119+
return []byte("eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9")
120+
121+
case PS256:
122+
return []byte("eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9")
123+
case PS384:
124+
return []byte("eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9")
125+
case PS512:
126+
return []byte("eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9")
127+
128+
default:
129+
// another algorithm? encode below
130+
}
112131
}
113132

114133
// returned err is always nil, see *Header.MarshalJSON
115-
buf, _ := json.Marshal(b.header)
134+
buf, _ := json.Marshal(header)
116135

117136
encoded := make([]byte, base64EncodedLen(len(buf)))
118137
base64Encode(encoded, buf)
119138

120139
return encoded
121140
}
122141

123-
func encodeClaims(claims encoding.BinaryMarshaler) (raw, encoded []byte, err error) {
142+
func encodeClaims(claims BinaryMarshaler) (raw, encoded []byte, err error) {
124143
raw, err = claims.MarshalBinary()
125144
if err != nil {
126145
return nil, nil, err
@@ -132,8 +151,8 @@ func encodeClaims(claims encoding.BinaryMarshaler) (raw, encoded []byte, err err
132151
return raw, encoded, nil
133152
}
134153

135-
func (b *TokenBuilder) signPayload(payload []byte) (signed, signature []byte, err error) {
136-
signature, err = b.signer.Sign(payload)
154+
func signPayload(signer Signer, payload []byte) (signed, signature []byte, err error) {
155+
signature, err = signer.Sign(payload)
137156
if err != nil {
138157
return nil, nil, err
139158
}

‎build_test.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package jwt
2+
3+
import (
4+
"encoding/base64"
5+
"fmt"
6+
"testing"
7+
)
8+
9+
func TestBuild(t *testing.T) {
10+
signer := NewHS256([]byte(`secret`))
11+
builder := NewTokenBuilder(signer)
12+
13+
claims := &StandardClaims{
14+
Audience: []string{"admin"},
15+
ID: "random-unique-string",
16+
}
17+
token, _ := builder.Build(claims)
18+
19+
fmt.Printf("Algorithm %v\n", token.Header().Algorithm)
20+
fmt.Printf("Type %v\n", token.Header().Type)
21+
fmt.Printf("Claims %v\n", string(token.RawClaims()))
22+
fmt.Printf("Payload %v\n", string(token.Payload()))
23+
fmt.Printf("Token %v\n", string(token.Raw()))
24+
}
25+
26+
func TestBuildWithHeader(t *testing.T) {
27+
f := func(signer Signer, header Header, want string) {
28+
t.Helper()
29+
30+
token, err := BuildWithHeader(signer, header, &StandardClaims{})
31+
if err != nil {
32+
t.Error(err)
33+
}
34+
35+
want = toBase64(want)
36+
raw := string(token.RawHeader())
37+
if raw != want {
38+
t.Errorf("want %v, got %v", want, raw)
39+
}
40+
}
41+
42+
f(
43+
NewHS256(nil),
44+
Header{Algorithm: HS256, Type: "JWT"},
45+
`{"alg":"HS256","typ":"JWT"}`,
46+
)
47+
f(
48+
NewHS512(nil),
49+
Header{Algorithm: HS512, Type: "jit"},
50+
`{"alg":"HS512","typ":"jit"}`,
51+
)
52+
f(
53+
NewHS512(nil),
54+
Header{Algorithm: Algorithm("OwO"), Type: "JWT"},
55+
`{"alg":"OwO","typ":"JWT"}`,
56+
)
57+
f(
58+
NewHS512(nil),
59+
Header{Algorithm: Algorithm("UwU"), Type: "jit"},
60+
`{"alg":"UwU","typ":"jit"}`,
61+
)
62+
}
63+
64+
func toBase64(s string) string {
65+
buf := make([]byte, base64EncodedLen(len(s)))
66+
base64.RawURLEncoding.Encode(buf, []byte(s))
67+
return string(buf)
68+
}

0 commit comments

Comments
 (0)
Please sign in to comment.