khenaidoo | ab1f7bd | 2019-11-14 14:00:27 -0500 | [diff] [blame] | 1 | package jwt |
| 2 | |
| 3 | import ( |
| 4 | "encoding/base64" |
| 5 | "encoding/json" |
| 6 | "strings" |
| 7 | "time" |
| 8 | ) |
| 9 | |
| 10 | // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). |
| 11 | // You can override it to use another time value. This is useful for testing or if your |
| 12 | // server uses a different time zone than your tokens. |
| 13 | var TimeFunc = time.Now |
| 14 | |
| 15 | // Parse methods use this callback function to supply |
| 16 | // the key for verification. The function receives the parsed, |
| 17 | // but unverified Token. This allows you to use properties in the |
| 18 | // Header of the token (such as `kid`) to identify which key to use. |
| 19 | type Keyfunc func(*Token) (interface{}, error) |
| 20 | |
| 21 | // A JWT Token. Different fields will be used depending on whether you're |
| 22 | // creating or parsing/verifying a token. |
| 23 | type Token struct { |
| 24 | Raw string // The raw token. Populated when you Parse a token |
| 25 | Method SigningMethod // The signing method used or to be used |
| 26 | Header map[string]interface{} // The first segment of the token |
| 27 | Claims Claims // The second segment of the token |
| 28 | Signature string // The third segment of the token. Populated when you Parse a token |
| 29 | Valid bool // Is the token valid? Populated when you Parse/Verify a token |
| 30 | } |
| 31 | |
| 32 | // Create a new Token. Takes a signing method |
| 33 | func New(method SigningMethod) *Token { |
| 34 | return NewWithClaims(method, MapClaims{}) |
| 35 | } |
| 36 | |
| 37 | func NewWithClaims(method SigningMethod, claims Claims) *Token { |
| 38 | return &Token{ |
| 39 | Header: map[string]interface{}{ |
| 40 | "typ": "JWT", |
| 41 | "alg": method.Alg(), |
| 42 | }, |
| 43 | Claims: claims, |
| 44 | Method: method, |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | // Get the complete, signed token |
| 49 | func (t *Token) SignedString(key interface{}) (string, error) { |
| 50 | var sig, sstr string |
| 51 | var err error |
| 52 | if sstr, err = t.SigningString(); err != nil { |
| 53 | return "", err |
| 54 | } |
| 55 | if sig, err = t.Method.Sign(sstr, key); err != nil { |
| 56 | return "", err |
| 57 | } |
| 58 | return strings.Join([]string{sstr, sig}, "."), nil |
| 59 | } |
| 60 | |
| 61 | // Generate the signing string. This is the |
| 62 | // most expensive part of the whole deal. Unless you |
| 63 | // need this for something special, just go straight for |
| 64 | // the SignedString. |
| 65 | func (t *Token) SigningString() (string, error) { |
| 66 | var err error |
| 67 | parts := make([]string, 2) |
| 68 | for i, _ := range parts { |
| 69 | var jsonValue []byte |
| 70 | if i == 0 { |
| 71 | if jsonValue, err = json.Marshal(t.Header); err != nil { |
| 72 | return "", err |
| 73 | } |
| 74 | } else { |
| 75 | if jsonValue, err = json.Marshal(t.Claims); err != nil { |
| 76 | return "", err |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | parts[i] = EncodeSegment(jsonValue) |
| 81 | } |
| 82 | return strings.Join(parts, "."), nil |
| 83 | } |
| 84 | |
| 85 | // Parse, validate, and return a token. |
| 86 | // keyFunc will receive the parsed token and should return the key for validating. |
| 87 | // If everything is kosher, err will be nil |
| 88 | func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { |
| 89 | return new(Parser).Parse(tokenString, keyFunc) |
| 90 | } |
| 91 | |
| 92 | func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { |
| 93 | return new(Parser).ParseWithClaims(tokenString, claims, keyFunc) |
| 94 | } |
| 95 | |
| 96 | // Encode JWT specific base64url encoding with padding stripped |
| 97 | func EncodeSegment(seg []byte) string { |
| 98 | return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") |
| 99 | } |
| 100 | |
| 101 | // Decode JWT specific base64url encoding with padding stripped |
| 102 | func DecodeSegment(seg string) ([]byte, error) { |
| 103 | if l := len(seg) % 4; l > 0 { |
| 104 | seg += strings.Repeat("=", 4-l) |
| 105 | } |
| 106 | |
| 107 | return base64.URLEncoding.DecodeString(seg) |
| 108 | } |