2 // ========================LICENSE_START=================================
5 // Copyright (C) 2022: Nordix Foundation
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 // ========================LICENSE_END===================================
27 "github.com/dgrijalva/jwt-go"
38 func NewJWT(privateKey []byte, publicKey []byte) JWT {
40 privateKey: privateKey,
45 func readFile(file string) []byte {
46 key, err := ioutil.ReadFile(file)
53 func (j JWT) createWithKey(ttl time.Duration, content interface{}, client, realm string) (string, error) {
54 key, err := jwt.ParseRSAPrivateKeyFromPEM(j.privateKey)
56 return "", fmt.Errorf("create: parse key: %w", err)
59 now := time.Now().UTC()
61 claims := make(jwt.MapClaims)
62 claims["dat"] = content // Our custom data.
63 claims["exp"] = now.Add(ttl).Unix() // The expiration time after which the token must be disregarded.
64 claims["iat"] = now.Unix() // The time at which the token was issued.
65 claims["nbf"] = now.Unix() // The time before which the token must be disregarded.
66 claims["jti"] = "myJWTId" + fmt.Sprint(now.UnixNano())
67 claims["sub"] = client
68 claims["iss"] = client
71 token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
72 tokenString, err := token.SignedString(key)
74 return "", fmt.Errorf("create: sign token: %w", err)
77 return tokenString, nil
80 func createWithSecret(ttl time.Duration, content interface{}, client, realm, secret string) (string, error) {
81 now := time.Now().UTC()
83 claims := make(jwt.MapClaims)
84 claims["dat"] = content // Our custom data.
85 claims["exp"] = now.Add(ttl).Unix() // The expiration time after which the token must be disregarded.
86 claims["iat"] = now.Unix() // The time at which the token was issued.
87 claims["nbf"] = now.Unix() // The time before which the token must be disregarded.
88 claims["jti"] = "myJWTId" + fmt.Sprint(now.UnixNano())
89 claims["sub"] = client
90 claims["iss"] = client
93 token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
95 return "", fmt.Errorf("create: sign token: %w", err)
101 func (j JWT) Validate(token string) (interface{}, error) {
102 key, err := jwt.ParseRSAPublicKeyFromPEM(j.publicKey)
104 return "", fmt.Errorf("validate: parse key: %w", err)
107 tok, err := jwt.Parse(token, func(jwtToken *jwt.Token) (interface{}, error) {
108 if _, ok := jwtToken.Method.(*jwt.SigningMethodRSA); !ok {
109 return nil, fmt.Errorf("unexpected method: %s", jwtToken.Header["alg"])
115 return nil, fmt.Errorf("validate: %w", err)
118 claims, ok := tok.Claims.(jwt.MapClaims)
119 if !ok || !tok.Valid {
120 return nil, fmt.Errorf("validate: invalid")
123 return claims["dat"], nil
126 func createPublicKeyFromPrivateKey(privkey_bytes []byte) []byte {
127 block, _ := pem.Decode([]byte(privkey_bytes))
128 var privateKey *rsa.PrivateKey
129 pkcs1, err := x509.ParsePKCS1PrivateKey(block.Bytes)
131 pkcs8, err := x509.ParsePKCS8PrivateKey(block.Bytes)
132 privateKey = pkcs8.(*rsa.PrivateKey)
140 publicKey := &privateKey.PublicKey
142 pubkey_bytes, err := x509.MarshalPKIXPublicKey(publicKey)
147 pubkey_pem := pem.EncodeToMemory(
156 func CreateJWT(privateKeyFile, secret, client, realm string) string {
158 prvKey := readFile(privateKeyFile)
159 pubKey := createPublicKeyFromPrivateKey(prvKey)
161 jwtToken := NewJWT(prvKey, pubKey)
163 // 1. Create a new JWT token.
164 tok, err := jwtToken.createWithKey(time.Hour, "Can be anything", client, realm)
169 // 2. Validate an existing JWT token.
170 _, err = jwtToken.Validate(tok)
176 // 1. Create a new JWT token.
177 tok, err := createWithSecret(time.Hour, "Can be anything", client, realm, secret)