github.com/twilio/twilio-go@v1.20.1/client/jwt/jwt.go (about) 1 package jwt 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "time" 8 9 "github.com/golang-jwt/jwt" 10 . "github.com/twilio/twilio-go/client/jwt/util" 11 ) 12 13 type TokenType string 14 15 type Jwt struct { 16 // The secret used to encode the JWT token. 17 SecretKey string 18 // The issuer of the JWT token. 19 Issuer string 20 // The subject of this JWT, omitted from the payload by default. 21 Subject string 22 // The algorithm used to encode the JWT token, defaults to 'HS256'. 23 Algorithm string 24 // Time in seconds before the JWT token is invalid. Defaults to now. 25 Nbf float64 26 // Time to live of the JWT in seconds; defaults to 1 hour. 27 Ttl float64 28 // Time in seconds since epoch this JWT is valid for. Override ttl if provided. 29 ValidUntil float64 30 31 DecodedHeaders map[string]interface{} 32 DecodedPayload map[string]interface{} 33 } 34 35 func (token *Jwt) generatePayload(payload map[string]interface{}) map[string]interface{} { 36 now := time.Now().Unix() 37 38 payload["iss"] = token.Issuer 39 payload["exp"] = float64(now) + token.Ttl 40 41 if token.Nbf != 0 { 42 payload["nbf"] = token.Nbf 43 } else { 44 payload["nbf"] = float64(now) 45 } 46 47 if token.ValidUntil != 0 { 48 payload["exp"] = token.ValidUntil 49 } 50 if token.Subject != "" { 51 payload["sub"] = token.Subject 52 } 53 54 return payload 55 } 56 57 func (token *Jwt) FromJwt(jwtStr string, key string) (*Jwt, error) { 58 verifyToken := true 59 if key == "" { 60 verifyToken = false 61 } 62 63 // Parse takes the token string and a function for looking up the key. The latter is especially 64 // useful if you use multiple keys for your application. The standard is to use 'kid' in the 65 // head of the token to identify which key to use, but the parsed token (head and claims) is provided 66 // to the callback, providing flexibility. 67 decodedToken, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) { 68 // Validate the alg is what you expect 69 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 70 return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) 71 } 72 73 return []byte(key), nil 74 }) 75 76 if decodedToken != nil { 77 if claims, ok := decodedToken.Claims.(jwt.MapClaims); ok { 78 if verifyToken && !decodedToken.Valid { 79 return nil, errors.New("token could not be validated") 80 } 81 jwtToken := Jwt{ 82 SecretKey: key, 83 Issuer: claims["iss"].(string), 84 Algorithm: decodedToken.Header["alg"].(string), 85 } 86 87 if val, ok := claims["sub"].(string); ok { 88 jwtToken.Subject = val 89 } 90 91 if val, ok := claims["exp"].(float64); ok { 92 jwtToken.ValidUntil = val 93 } 94 95 nbf, err := strconv.ParseFloat(fmt.Sprintf("%v", claims["nbf"]), 64) 96 if err == nil { 97 jwtToken.Nbf = nbf 98 } 99 100 jwtToken.DecodedHeaders = decodedToken.Header 101 jwtToken.DecodedPayload = claims 102 return &jwtToken, nil 103 } else { 104 return nil, err 105 } 106 } 107 108 return nil, errors.New("error decoding JWT token") 109 } 110 111 func (token *Jwt) Payload() map[string]interface{} { 112 if token.DecodedPayload == nil { 113 token.DecodedPayload = token.generatePayload(map[string]interface{}{}) 114 } 115 116 return token.DecodedPayload 117 } 118 119 func (token *Jwt) Headers() map[string]interface{} { 120 if token.DecodedHeaders == nil { 121 token.DecodedHeaders = token.generateHeaders() 122 } 123 124 return token.DecodedHeaders 125 } 126 127 func (token *Jwt) generateHeaders() map[string]interface{} { 128 headers := make(map[string]interface{}) 129 headers["alg"] = HS256 130 headers["typ"] = JWT 131 return headers 132 } 133 134 // Encode this JWT struct into a string. 135 // algorithm - algorithm used to encode the JWT that overrides the default 136 // ttl - specify ttl to override the default 137 func (token *Jwt) ToJwt(generateHeaders, generatePayload func() map[string]interface{}) (string, error) { 138 if token.SecretKey == "" { 139 panic("JWT does not have a signing key configured.") 140 } 141 142 headers := generateHeaders() 143 payload := generatePayload() 144 if signedToken, err := SignTokenWithHMAC(headers, payload, token.SecretKey); err != nil { 145 return "", err 146 } else { 147 return signedToken, nil 148 } 149 } 150 151 func SignTokenWithHMAC(headers, payload map[string]interface{}, secret string) (string, error) { 152 claims := jwt.MapClaims{} 153 154 for k, v := range payload { 155 claims[k] = v 156 } 157 158 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 159 160 for hk, hv := range headers { 161 jwtToken.Header[hk] = hv 162 } 163 164 if tokenString, err := jwtToken.SignedString([]byte(secret)); err != nil { 165 return "", err 166 } else { 167 return tokenString, nil 168 } 169 }