/
jwt.go
162 lines (133 loc) · 4.15 KB
/
jwt.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2021 Harran Ali <harran.m@gmail.com>. All rights reserved.
// Use of this source code is governed by MIT-style
// license that can be found in the LICENSE file.
package jwt
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
// JWTUtil pakcage struct
type JWTUtil struct{}
// DefaultTokenLifeSpan is the default ttl for jwt token
var DefaultTokenLifeSpan time.Duration = 15 * time.Minute //15 minutes
// DefaultRefreshTokenLifeSpanHours is the default ttl for jwt refresh token
var DefaultRefreshTokenLifeSpanHours time.Duration = 24 * time.Hour //24 hours
var USER_ID = "userID"
var JWT *JWTUtil
// New initiates Jwt struct
func New() *JWTUtil {
JWT = &JWTUtil{}
return JWT
}
//Resolve returns initiated jwt token
func Resolve() *JWTUtil {
return JWT
}
// CreateToken generates new jwt token with the given user id
func (j *JWTUtil) CreateToken(userID uint) (string, error) {
claims := jwt.MapClaims{}
var duration time.Duration
durationStr := os.Getenv("JWT_LIFESPAN_MINUTES")
if durationStr == "" {
duration = DefaultTokenLifeSpan
} else {
d, _ := strconv.ParseInt(durationStr, 10, 64)
duration = time.Duration(d) * time.Minute
}
claims[USER_ID] = userID
claims["authorized"] = true
claims["exp"] = time.Now().Add(duration).Unix()
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
secret := os.Getenv("JWT_SECRET")
if secret == "" {
return "", errors.New("missing jwt token secret")
}
token, err := jwtToken.SignedString([]byte(secret))
if err != nil {
return "", err
}
return token, nil
}
// CreateRefreshToken generates new jwt refresh token with the given user id
func (j *JWTUtil) CreateRefreshToken(userID uint) (string, error) {
claims := jwt.MapClaims{}
var duration time.Duration
durationStrHours := os.Getenv("JWT_REFRESH_TOKEN_LIFESPAN_HOURS")
if durationStrHours == "" {
duration = DefaultRefreshTokenLifeSpanHours
} else {
d, _ := strconv.ParseInt(durationStrHours, 10, 64)
duration = time.Duration(d) * time.Hour
}
claims[USER_ID] = userID
claims["exp"] = time.Now().Add(duration).Unix()
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
secret := os.Getenv("JWT_REFRESH_TOKEN_SECRET")
if secret == "" {
return "", errors.New("missing jwt token refresh secret")
}
token, err := jwtToken.SignedString([]byte(secret))
if err != nil {
return "", err
}
return token, nil
}
//ExtractToken extracts the token from the request header
func (j *JWTUtil) ExtractToken(c *gin.Context) (token string, err error) {
sentTokenSlice := c.Request.Header["Authorization"]
if len(sentTokenSlice) == 0 {
return "", errors.New("Missing authorization token")
}
sentTokenSlice = strings.Split(sentTokenSlice[0], " ")
if len(sentTokenSlice) != 2 {
return "", errors.New("Something wrong with the token")
}
return sentTokenSlice[1], nil
}
// DecodeToken decodes a given token and returns the user id
func (j *JWTUtil) DecodeToken(tokenString string) (userID uint, err error) {
// validate the token
_, err = j.ValidateToken(tokenString)
if err != nil {
return 0, err
}
//extract claims
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("JWT_SECRET")), nil
})
claims := token.Claims.(jwt.MapClaims)
delete(claims, "authorized")
delete(claims, "exp")
id, err := strconv.ParseInt(fmt.Sprintf("%v", claims[USER_ID]), 10, 32)
if err != nil {
return 0, err
}
userID = uint(id)
return userID, nil
}
// ValidateToken makes sure the given token is valid
func (j *JWTUtil) ValidateToken(tokenString string) (bool, error) {
// parse the token string
_, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// validate the signing method
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("invalid signing method: %s", token.Method.Alg())
}
return []byte(os.Getenv("JWT_SECRET")), nil
})
if err != nil {
return false, err
}
return true, nil
}
// RefreshToken generates a new token based on the refresh token
// TODO: implement
func RefreshToken(token string, refreshToken string) (newToken string, err error) {
return
}