token.go raw

   1  package jwt
   2  
   3  import (
   4  	"encoding/base64"
   5  	"encoding/json"
   6  	"strings"
   7  	"time"
   8  )
   9  
  10  // DecodePaddingAllowed will switch the codec used for decoding JWTs respectively. Note that the JWS RFC7515
  11  // states that the tokens will utilize a Base64url encoding with no padding. Unfortunately, some implementations
  12  // of JWT are producing non-standard tokens, and thus require support for decoding. Note that this is a global
  13  // variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe.
  14  // To use the non-recommended decoding, set this boolean to `true` prior to using this package.
  15  var DecodePaddingAllowed bool
  16  
  17  // DecodeStrict will switch the codec used for decoding JWTs into strict mode.
  18  // In this mode, the decoder requires that trailing padding bits are zero, as described in RFC 4648 section 3.5.
  19  // Note that this is a global variable, and updating it will change the behavior on a package level, and is also NOT go-routine safe.
  20  // To use strict decoding, set this boolean to `true` prior to using this package.
  21  var DecodeStrict bool
  22  
  23  // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
  24  // You can override it to use another time value.  This is useful for testing or if your
  25  // server uses a different time zone than your tokens.
  26  var TimeFunc = time.Now
  27  
  28  // Keyfunc will be used by the Parse methods as a callback function to supply
  29  // the key for verification.  The function receives the parsed,
  30  // but unverified Token.  This allows you to use properties in the
  31  // Header of the token (such as `kid`) to identify which key to use.
  32  type Keyfunc func(*Token) (interface{}, error)
  33  
  34  // Token represents a JWT Token.  Different fields will be used depending on whether you're
  35  // creating or parsing/verifying a token.
  36  type Token struct {
  37  	Raw       string                 // The raw token.  Populated when you Parse a token
  38  	Method    SigningMethod          // The signing method used or to be used
  39  	Header    map[string]interface{} // The first segment of the token
  40  	Claims    Claims                 // The second segment of the token
  41  	Signature string                 // The third segment of the token.  Populated when you Parse a token
  42  	Valid     bool                   // Is the token valid?  Populated when you Parse/Verify a token
  43  }
  44  
  45  // New creates a new Token with the specified signing method and an empty map of claims.
  46  func New(method SigningMethod) *Token {
  47  	return NewWithClaims(method, MapClaims{})
  48  }
  49  
  50  // NewWithClaims creates a new Token with the specified signing method and claims.
  51  func NewWithClaims(method SigningMethod, claims Claims) *Token {
  52  	return &Token{
  53  		Header: map[string]interface{}{
  54  			"typ": "JWT",
  55  			"alg": method.Alg(),
  56  		},
  57  		Claims: claims,
  58  		Method: method,
  59  	}
  60  }
  61  
  62  // SignedString creates and returns a complete, signed JWT.
  63  // The token is signed using the SigningMethod specified in the token.
  64  func (t *Token) SignedString(key interface{}) (string, error) {
  65  	var sig, sstr string
  66  	var err error
  67  	if sstr, err = t.SigningString(); err != nil {
  68  		return "", err
  69  	}
  70  	if sig, err = t.Method.Sign(sstr, key); err != nil {
  71  		return "", err
  72  	}
  73  	return strings.Join([]string{sstr, sig}, "."), nil
  74  }
  75  
  76  // SigningString generates the signing string.  This is the
  77  // most expensive part of the whole deal.  Unless you
  78  // need this for something special, just go straight for
  79  // the SignedString.
  80  func (t *Token) SigningString() (string, error) {
  81  	var err error
  82  	var jsonValue []byte
  83  
  84  	if jsonValue, err = json.Marshal(t.Header); err != nil {
  85  		return "", err
  86  	}
  87  	header := EncodeSegment(jsonValue)
  88  
  89  	if jsonValue, err = json.Marshal(t.Claims); err != nil {
  90  		return "", err
  91  	}
  92  	claim := EncodeSegment(jsonValue)
  93  
  94  	return strings.Join([]string{header, claim}, "."), nil
  95  }
  96  
  97  // Parse parses, validates, verifies the signature and returns the parsed token.
  98  // keyFunc will receive the parsed token and should return the cryptographic key
  99  // for verifying the signature.
 100  // The caller is strongly encouraged to set the WithValidMethods option to
 101  // validate the 'alg' claim in the token matches the expected algorithm.
 102  // For more details about the importance of validating the 'alg' claim,
 103  // see https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
 104  func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
 105  	return NewParser(options...).Parse(tokenString, keyFunc)
 106  }
 107  
 108  // ParseWithClaims is a shortcut for NewParser().ParseWithClaims().
 109  //
 110  // Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims),
 111  // make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the
 112  // proper memory for it before passing in the overall claims, otherwise you might run into a panic.
 113  func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) {
 114  	return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc)
 115  }
 116  
 117  // EncodeSegment encodes a JWT specific base64url encoding with padding stripped
 118  //
 119  // Deprecated: In a future release, we will demote this function to a non-exported function, since it
 120  // should only be used internally
 121  func EncodeSegment(seg []byte) string {
 122  	return base64.RawURLEncoding.EncodeToString(seg)
 123  }
 124  
 125  // DecodeSegment decodes a JWT specific base64url encoding with padding stripped
 126  //
 127  // Deprecated: In a future release, we will demote this function to a non-exported function, since it
 128  // should only be used internally
 129  func DecodeSegment(seg string) ([]byte, error) {
 130  	encoding := base64.RawURLEncoding
 131  
 132  	if DecodePaddingAllowed {
 133  		if l := len(seg) % 4; l > 0 {
 134  			seg += strings.Repeat("=", 4-l)
 135  		}
 136  		encoding = base64.URLEncoding
 137  	}
 138  
 139  	if DecodeStrict {
 140  		encoding = encoding.Strict()
 141  	}
 142  	return encoding.DecodeString(seg)
 143  }
 144