-
Notifications
You must be signed in to change notification settings - Fork 1
/
token.go
92 lines (82 loc) · 2.61 KB
/
token.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Package auth contains code to ensure users are authorized to use the server after they have logged in.
package auth
import (
"fmt"
jwt "github.com/golang-jwt/jwt/v4"
)
type (
// TokenizerConfig contains fields which describe a Tokenizer.
TokenizerConfig struct {
// TimeFunc is a function which should supply the current time since the unix epoch.
// This is used for setting token lifespan.
TimeFunc func() int64
// ValidSec is the length of time the token is valid from the issuing time, in seconds.
ValidSec int64
}
// JwtTokenizer creates java web tokens.
JwtTokenizer struct {
method jwt.SigningMethod
key interface{}
TokenizerConfig
}
// jwtUserClaims appends user points to the standard jwt claims.
jwtUserClaims struct {
Points int `json:"points"`
jwt.StandardClaims // username stored in Subject ("sub") field
}
)
// NewTokenizer creates a Tokenizer that users the random number generator to generate tokens.
func (cfg TokenizerConfig) NewTokenizer(key interface{}) (*JwtTokenizer, error) {
if err := cfg.validate(key); err != nil {
return nil, fmt.Errorf("creating tokenizer: validation: %w", err)
}
t := JwtTokenizer{
method: jwt.SigningMethodHS256,
key: key,
TokenizerConfig: cfg,
}
return &t, nil
}
// validate ensures the configuration has no errors.
func (cfg TokenizerConfig) validate(key interface{}) error {
switch {
case key == nil:
return fmt.Errorf("log required")
case cfg.TimeFunc == nil:
return fmt.Errorf("time func required")
case cfg.ValidSec <= 0:
return fmt.Errorf("non-negative valid seconds required")
}
return nil
}
// Create converts a user to a token string.
func (j *JwtTokenizer) Create(username string, points int) (string, error) {
now := j.TimeFunc()
expiresAt := now + j.ValidSec
stdClaims := jwt.StandardClaims{
Subject: username,
NotBefore: now,
ExpiresAt: expiresAt,
}
claims := jwtUserClaims{
Points: points,
StandardClaims: stdClaims,
}
token := jwt.NewWithClaims(j.method, claims)
return token.SignedString(j.key)
}
// ReadUsername extracts the username from the token string.
func (j *JwtTokenizer) ReadUsername(tokenString string) (string, error) {
var claims jwtUserClaims
if _, err := jwt.ParseWithClaims(tokenString, &claims, j.keyFunc); err != nil {
return "", err
}
return claims.Subject, nil
}
// keyFunc ensures the key type (method) of the token is correct before returning the key.
func (j *JwtTokenizer) keyFunc(t *jwt.Token) (interface{}, error) {
if t.Method != j.method {
return nil, fmt.Errorf("incorrect authorization signing method")
}
return j.key, nil
}