Generation and Verify JWT token in golang
Use HS256
or RS256
to sign and authorization is common JWT methods
Create the JWT token
1package util
2
3import "github.com/golang-jwt/jwt/v5"
4
5// retrieve JWT key from .env file
6var privateKey = []byte(os.Getenv("JWT_PRIVATE_KEY"))
7
8// generate JWT token
9func GenerateJWT(user model.User) (string, error) {
10 tokenTTL, _ := strconv.Atoi(os.Getenv("TOKEN_TTL"))
11 //log.Println(time.Now())
12 //log.Println(time.Now().Add(time.Second * time.Duration(tokenTTL)))
13 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
14 "id": user.ID,
15 "role": user.RoleID,
16 "iat": time.Now().Unix(),
17 "eat": time.Now().Add(time.Second * time.Duration(tokenTTL)).Unix(),
18 })
19 return token.SignedString(privateKey)
20}
Validate the JWT
1// validate JWT token
2func ValidateJWT(context *gin.Context) error {
3 token, err := getToken(context)
4 if err != nil {
5 return err
6 }
7 _, ok := token.Claims.(jwt.MapClaims)
8 if ok && token.Valid {
9 return nil
10 }
11 return errors.New("invalid token provided")
12}
13
14// check token validity
15func getToken(context *gin.Context) (*jwt.Token, error) {
16 tokenString := getTokenFromRequest(context)
17 token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
18 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
19 return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
20 }
21
22 return privateKey, nil
23 })
24 return token, err
25}
26
27// extract token from request Authorization header
28func getTokenFromRequest(context *gin.Context) string {
29 bearerToken := context.Request.Header.Get("Authorization")
30 splitToken := strings.Split(bearerToken, " ")
31 if len(splitToken) == 2 {
32 return splitToken[1]
33 }
34 return ""
35}
If use RS256
to sign and verify JWT token
- generation the PKI
1# The makefile
2.PHONY: cert
3cert:
4 openssl genrsa -out cert/id_rsa 4096
5 openssl rsa -in cert/id_rsa -pubout -out cert/id_rsa.pub
- use the private key to sign token
1package main
2
3import (
4 "fmt"
5 "io/ioutil"
6 "log"
7 "time"
8
9 "github.com/you/client/internal/pkg/token"
10)
11
12func main() {
13 prvKey, err := ioutil.ReadFile("cert/id_rsa")
14 if err != nil {
15 log.Fatalln(err)
16 }
17 pubKey, err := ioutil.ReadFile("cert/id_rsa.pub")
18 if err != nil {
19 log.Fatalln(err)
20 }
21
22 jwtToken := token.NewJWT(prvKey, pubKey)
23
24 // 1. Create a new JWT token.
25 tok, err := jwtToken.Create(time.Hour, "Can be anything")
26 if err != nil {
27 log.Fatalln(err)
28 }
29 fmt.Println("TOKEN:", tok)
30
31 // 2. Validate an existing JWT token.
32 content, err := jwtToken.Validate(tok)
33 if err != nil {
34 log.Fatalln(err)
35 }
36 fmt.Println("CONTENT:", content)
37}
- use the public key to verify
1package token
2
3import (
4 "fmt"
5 "time"
6
7 "github.com/dgrijalva/jwt-go"
8)
9
10type JWT struct {
11 privateKey []byte
12 publicKey []byte
13}
14
15func NewJWT(privateKey []byte, publicKey []byte) JWT {
16 return JWT{
17 privateKey: privateKey,
18 publicKey: publicKey,
19 }
20}
21
22func (j JWT) Create(ttl time.Duration, content interface{}) (string, error) {
23 key, err := jwt.ParseRSAPrivateKeyFromPEM(j.privateKey)
24 if err != nil {
25 return "", fmt.Errorf("create: parse key: %w", err)
26 }
27
28 now := time.Now().UTC()
29
30 claims := make(jwt.MapClaims)
31 claims["dat"] = content // Our custom data.
32 claims["exp"] = now.Add(ttl).Unix() // The expiration time after which the token must be disregarded.
33 claims["iat"] = now.Unix() // The time at which the token was issued.
34 claims["nbf"] = now.Unix() // The time before which the token must be disregarded.
35
36 token, err := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key)
37 if err != nil {
38 return "", fmt.Errorf("create: sign token: %w", err)
39 }
40
41 return token, nil
42}
43
44func (j JWT) Validate(token string) (interface{}, error) {
45 key, err := jwt.ParseRSAPublicKeyFromPEM(j.publicKey)
46 if err != nil {
47 return "", fmt.Errorf("validate: parse key: %w", err)
48 }
49
50 tok, err := jwt.Parse(token, func(jwtToken *jwt.Token) (interface{}, error) {
51 if _, ok := jwtToken.Method.(*jwt.SigningMethodRSA); !ok {
52 return nil, fmt.Errorf("unexpected method: %s", jwtToken.Header["alg"])
53 }
54
55 return key, nil
56 })
57 if err != nil {
58 return nil, fmt.Errorf("validate: %w", err)
59 }
60
61 claims, ok := tok.Claims.(jwt.MapClaims)
62 if !ok || !tok.Valid {
63 return nil, fmt.Errorf("validate: invalid")
64 }
65
66 return claims["dat"], nil
67}