github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/appengine/login/googlesignin/jwt-go/jwt.go (about) 1 package jwt 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "net/http" 7 "strings" 8 "time" 9 ) 10 11 // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). 12 // You can override it to use another time value. This is useful for testing or if your 13 // server uses a different time zone than your tokens. 14 var TimeFunc = time.Now 15 16 // Parse methods use this callback function to supply 17 // the key for verification. The function receives the parsed, 18 // but unverified Token. This allows you to use propries in the 19 // Header of the token (such as `kid`) to identify which key to use. 20 type Keyfunc func(*Token) (interface{}, error) 21 22 // A JWT Token. Different fields will be used depending on whether you're 23 // creating or parsing/verifying a token. 24 type Token struct { 25 Raw string // The raw token. Populated when you Parse a token 26 Method SigningMethod // The signing method used or to be used 27 Header map[string]interface{} // The first segment of the token 28 Claims map[string]interface{} // The second segment of the token 29 Signature string // The third segment of the token. Populated when you Parse a token 30 Valid bool // Is the token valid? Populated when you Parse/Verify a token 31 } 32 33 // Create a new Token. Takes a signing method 34 func New(method SigningMethod) *Token { 35 return &Token{ 36 Header: map[string]interface{}{ 37 "typ": "JWT", 38 "alg": method.Alg(), 39 }, 40 Claims: make(map[string]interface{}), 41 Method: method, 42 } 43 } 44 45 // Get the complete, signed token 46 func (t *Token) SignedString(key interface{}) (string, error) { 47 var sig, sstr string 48 var err error 49 if sstr, err = t.SigningString(); err != nil { 50 return "", err 51 } 52 if sig, err = t.Method.Sign(sstr, key); err != nil { 53 return "", err 54 } 55 return strings.Join([]string{sstr, sig}, "."), nil 56 } 57 58 // Generate the signing string. This is the 59 // most expensive part of the whole deal. Unless you 60 // need this for something special, just go straight for 61 // the SignedString. 62 func (t *Token) SigningString() (string, error) { 63 var err error 64 parts := make([]string, 2) 65 for i, _ := range parts { 66 var source map[string]interface{} 67 if i == 0 { 68 source = t.Header 69 } else { 70 source = t.Claims 71 } 72 73 var jsonValue []byte 74 if jsonValue, err = json.Marshal(source); err != nil { 75 return "", err 76 } 77 78 parts[i] = EncodeSegment(jsonValue) 79 } 80 return strings.Join(parts, "."), nil 81 } 82 83 // Parse, validate, and return a token. 84 // keyFunc will receive the parsed token and should return the key for validating. 85 // If everything is kosher, err will be nil 86 func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { 87 parts := strings.Split(tokenString, ".") 88 if len(parts) != 3 { 89 return nil, &ValidationError{err: "token contains an invalid number of segments", Errors: ValidationErrorMalformed} 90 } 91 92 var err error 93 token := &Token{Raw: tokenString} 94 // parse Header 95 var headerBytes []byte 96 if headerBytes, err = DecodeSegment(parts[0]); err != nil { 97 return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} 98 } 99 if err = json.Unmarshal(headerBytes, &token.Header); err != nil { 100 return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} 101 } 102 103 // parse Claims 104 var claimBytes []byte 105 if claimBytes, err = DecodeSegment(parts[1]); err != nil { 106 return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} 107 } 108 if err = json.Unmarshal(claimBytes, &token.Claims); err != nil { 109 return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed} 110 } 111 112 // Lookup signature method 113 if method, ok := token.Header["alg"].(string); ok { 114 if token.Method = GetSigningMethod(method); token.Method == nil { 115 return token, &ValidationError{err: "signing method (alg) is unavailable.", Errors: ValidationErrorUnverifiable} 116 } 117 } else { 118 return token, &ValidationError{err: "signing method (alg) is unspecified.", Errors: ValidationErrorUnverifiable} 119 } 120 121 // Lookup key 122 var key interface{} 123 if keyFunc == nil { 124 // keyFunc was not provided. short circuiting validation 125 return token, &ValidationError{err: "no Keyfunc was provided.", Errors: ValidationErrorUnverifiable} 126 } 127 if key, err = keyFunc(token); err != nil { 128 // keyFunc returned an error 129 return token, &ValidationError{err: err.Error(), Errors: ValidationErrorUnverifiable} 130 } 131 132 // Check expiration times 133 vErr := &ValidationError{} 134 now := TimeFunc().Unix() 135 if exp, ok := token.Claims["exp"].(float64); ok { 136 if now > int64(exp) { 137 vErr.err = "token is expired" 138 vErr.Errors |= ValidationErrorExpired 139 } 140 } 141 if nbf, ok := token.Claims["nbf"].(float64); ok { 142 if now < int64(nbf) { 143 vErr.err = "token is not valid yet" 144 vErr.Errors |= ValidationErrorNotValidYet 145 } 146 } 147 148 // Perform validation 149 if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err != nil { 150 vErr.err = err.Error() 151 vErr.Errors |= ValidationErrorSignatureInvalid 152 } 153 154 if vErr.valid() { 155 token.Valid = true 156 return token, nil 157 } 158 159 return token, vErr 160 } 161 162 // Try to find the token in an http.Request. 163 // This method will call ParseMultipartForm if there's no token in the header. 164 // Currently, it looks in the Authorization header as well as 165 // looking for an 'access_token' request parameter in req.Form. 166 func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) { 167 168 // Look for an Authorization header 169 if ah := req.Header.Get("Authorization"); ah != "" { 170 // Should be a bearer token 171 if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" { 172 return Parse(ah[7:], keyFunc) 173 } 174 } 175 176 // Look for "access_token" parameter 177 req.ParseMultipartForm(10e6) 178 if tokStr := req.Form.Get("access_token"); tokStr != "" { 179 return Parse(tokStr, keyFunc) 180 } 181 182 return nil, ErrNoTokenInRequest 183 184 } 185 186 // Encode JWT specific base64url encoding with padding stripped 187 func EncodeSegment(seg []byte) string { 188 return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=") 189 } 190 191 // Decode JWT specific base64url encoding with padding stripped 192 func DecodeSegment(seg string) ([]byte, error) { 193 if l := len(seg) % 4; l > 0 { 194 seg += strings.Repeat("=", 4-l) 195 } 196 197 return base64.URLEncoding.DecodeString(seg) 198 }