validateToken verifies the signature and expiration of the jwt, and if validation passes, returns a slice of strings, where the first element is the extracted userId and the rest are groupIds encoded in the jwt.
(jwtStr string)
| 168 | // returns a slice of strings, where the first element is the extracted userId |
| 169 | // and the rest are groupIds encoded in the jwt. |
| 170 | func validateToken(jwtStr string) (*userData, error) { |
| 171 | claims, err := x.ParseJWT(jwtStr) |
| 172 | if err != nil { |
| 173 | return nil, err |
| 174 | } |
| 175 | // by default, the MapClaims.Valid will return true if the exp field is not set |
| 176 | // here we enforce the checking to make sure that the refresh token has not expired |
| 177 | if exp, err := claims.GetExpirationTime(); err != nil || exp == nil { |
| 178 | return nil, errors.Errorf("Token is expired") // the same error msg that's used inside jwt-go |
| 179 | } |
| 180 | |
| 181 | userId, ok := claims["userid"].(string) |
| 182 | if !ok { |
| 183 | return nil, errors.Errorf("userid in claims is not a string:%v", userId) |
| 184 | } |
| 185 | |
| 186 | /* |
| 187 | * Since, JSON numbers follow JavaScript's double-precision floating-point |
| 188 | * format . . . |
| 189 | * -- references: https://restfulapi.net/json-data-types/ |
| 190 | * -- https://www.tutorialspoint.com/json/json_data_types.htm |
| 191 | * . . . and fraction in IEEE 754 double precision binary floating-point |
| 192 | * format has 52 bits, . . . |
| 193 | * -- references: https://en.wikipedia.org/wiki/Double-precision_floating-point_format |
| 194 | * . . . the namespace field of the struct userData below can |
| 195 | * only accomodate a maximum value of (1 << 52) despite it being declared as |
| 196 | * uint64. Numbers bigger than this are likely to fail the test. |
| 197 | */ |
| 198 | namespace, ok := claims["namespace"].(float64) |
| 199 | if !ok { |
| 200 | return nil, errors.Errorf("namespace in claims is not valid:%v", namespace) |
| 201 | } |
| 202 | |
| 203 | groups, ok := claims["groups"].([]interface{}) |
| 204 | var groupIds []string |
| 205 | if ok { |
| 206 | groupIds = make([]string, 0, len(groups)) |
| 207 | for _, group := range groups { |
| 208 | groupId, ok := group.(string) |
| 209 | if !ok { |
| 210 | // This shouldn't happen. So, no need to make the client try to refresh the tokens. |
| 211 | return nil, errors.Errorf("unable to convert group to string:%v", group) |
| 212 | } |
| 213 | |
| 214 | groupIds = append(groupIds, groupId) |
| 215 | } |
| 216 | } |
| 217 | return &userData{namespace: uint64(namespace), userId: userId, groupIds: groupIds}, nil |
| 218 | } |
| 219 | |
| 220 | // validateLoginRequest validates that the login request has either the refresh token or the |
| 221 | // <user id, password> pair |