github.com/twilio/twilio-go@v1.20.1/client/jwt/access_token.go (about) 1 package jwt 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 "time" 8 9 . "github.com/twilio/twilio-go/client/jwt/util" 10 ) 11 12 type AccessToken struct { 13 baseJwt *Jwt 14 // List of permissions that the token grants 15 Grants []BaseGrant `json:"grants,omitempty"` 16 // Twilio Account SID 17 AccountSid string `json:"account_sid,omitempty"` 18 // API key 19 SigningKeySid string `json:"signing_key_sid,omitempty"` 20 // User's identity 21 Identity string `json:"identity,omitempty"` 22 // User's region 23 Region interface{} `json:"region,omitempty"` 24 } 25 26 type AccessTokenParams struct { 27 // Twilio Account sid 28 AccountSid string 29 // The issuer of the token 30 SigningKeySid string 31 // The secret used to sign the token 32 Secret string 33 // Identity of the token issuer 34 Identity string 35 // User's Region 36 Region string 37 // Time in secs since epoch before which this JWT is invalid, defaults to now 38 Nbf float64 39 // Time to live of the JWT in seconds, defaults to 1 hour 40 Ttl float64 41 // Time in secs since epoch this JWT is valid for. Overrides ttl if provided. 42 ValidUntil float64 43 // Access permissions granted to this token 44 Grants []BaseGrant 45 } 46 47 func CreateAccessToken(params AccessTokenParams) AccessToken { 48 return AccessToken{ 49 baseJwt: &Jwt{ 50 SecretKey: params.Secret, 51 Issuer: params.SigningKeySid, 52 Subject: params.AccountSid, 53 Algorithm: HS256, 54 Nbf: params.Nbf, 55 Ttl: Max(params.Ttl, 3600), 56 ValidUntil: params.ValidUntil, 57 }, 58 Grants: params.Grants, 59 AccountSid: params.AccountSid, 60 SigningKeySid: params.SigningKeySid, 61 Identity: params.Identity, 62 Region: params.Region, 63 } 64 } 65 66 func (token *AccessToken) Payload() map[string]interface{} { 67 if token.baseJwt.DecodedPayload == nil { 68 token.baseJwt.DecodedPayload = token.GeneratePayload() 69 } 70 71 return token.baseJwt.DecodedPayload 72 } 73 74 func (token *AccessToken) AddGrant(grant BaseGrant) { 75 if grant == nil { 76 panic("Grant to add is nil") 77 } 78 token.Grants = append(token.Grants, grant) 79 } 80 81 func (token *AccessToken) Headers() map[string]interface{} { 82 if token.baseJwt.DecodedHeaders == nil { 83 token.baseJwt.DecodedHeaders = token.generateHeaders() 84 } 85 86 return token.baseJwt.DecodedHeaders 87 } 88 89 func (token *AccessToken) generateHeaders() map[string]interface{} { 90 headers := make(map[string]interface{}) 91 headers["cty"] = CType 92 93 if token.Region != "" { 94 headers["twr"] = token.Region 95 } 96 97 headers["alg"] = HS256 98 headers["typ"] = JWT 99 100 return headers 101 } 102 103 func (token *AccessToken) GeneratePayload() map[string]interface{} { 104 now := float64(time.Now().Unix()) 105 106 grants := make(map[string]interface{}) 107 for _, grant := range token.Grants { 108 grants[grant.Key()] = grant.ToPayload() 109 } 110 111 payload := map[string]interface{}{ 112 "jti": fmt.Sprintf("%s-%s", token.SigningKeySid, strconv.Itoa(int(now))), 113 "grants": grants, 114 } 115 116 if token.Identity != "" { 117 val := payload["grants"].(map[string]interface{}) 118 val["identity"] = token.Identity 119 } 120 121 payload["iss"] = token.baseJwt.Issuer 122 payload["exp"] = now + token.baseJwt.Ttl 123 124 if token.baseJwt.Nbf != 0 { 125 payload["nbf"] = token.baseJwt.Nbf 126 } else { 127 payload["nbf"] = now 128 } 129 130 if token.baseJwt.ValidUntil != 0 { 131 payload["exp"] = token.baseJwt.ValidUntil 132 } 133 if token.baseJwt.Subject != "" { 134 payload["sub"] = token.baseJwt.Subject 135 } 136 137 return payload 138 } 139 140 // Encode this JWT struct into a string. 141 // algorithm - algorithm used to encode the JWT that overrides the default 142 // ttl - specify ttl to override the default 143 func (token *AccessToken) ToJwt() (string, error) { 144 signedToken, err := token.baseJwt.ToJwt(token.generateHeaders, token.GeneratePayload) 145 if err != nil { 146 return "", err 147 } 148 return signedToken, nil 149 } 150 151 func decodeGrants(grants interface{}) []BaseGrant { 152 var decodedGrants []BaseGrant 153 154 for k, v := range grants.(map[string]interface{}) { 155 var grant BaseGrant 156 if data, err := json.Marshal(v); err == nil { 157 switch k { 158 case "chat": 159 grant = &ChatGrant{} 160 case "rtc": 161 grant = &ConversationsGrant{} 162 case "ip_messaging": 163 grant = &IpMessagingGrant{} 164 case "data_sync": 165 grant = &SyncGrant{} 166 case "task_router": 167 grant = &TaskRouterGrant{} 168 case "video": 169 grant = &VideoGrant{} 170 case "voice": 171 grant = &VoiceGrant{} 172 case "player": 173 grant = &PlaybackGrant{} 174 } 175 176 if errJson := json.Unmarshal(data, &grant); errJson == nil { 177 decodedGrants = append(decodedGrants, grant) 178 } 179 } 180 } 181 182 return decodedGrants 183 } 184 185 // Decode a JWT string into a Jwt struct. 186 // jwt - JWT string 187 // key - string key used to verify the JWT signature; if not provided, then validation is skipped 188 func (token *AccessToken) FromJwt(jwtStr string, key string) (*AccessToken, error) { 189 baseToken, err := token.baseJwt.FromJwt(jwtStr, key) 190 if err != nil { 191 return nil, err 192 } 193 194 decodedToken := &AccessToken{ 195 baseJwt: baseToken, 196 Grants: decodeGrants(baseToken.Payload()["grants"]), 197 AccountSid: baseToken.Payload()["sub"].(string), 198 SigningKeySid: baseToken.Payload()["iss"].(string), 199 } 200 201 if val, ok := baseToken.Headers()["twr"]; ok { 202 decodedToken.Region = val 203 } 204 if val, ok := baseToken.Payload()["grants"]; ok { 205 if iVal, iOk := val.(map[string]interface{})["identity"]; iOk { 206 decodedToken.Identity = iVal.(string) 207 } 208 } 209 210 return decodedToken, nil 211 }