token.go raw

   1  package jwt
   2  
   3  import (
   4  	"crypto"
   5  	"encoding/base64"
   6  	"encoding/json"
   7  )
   8  
   9  // Keyfunc will be used by the Parse methods as a callback function to supply
  10  // the key for verification.  The function receives the parsed, but unverified
  11  // Token.  This allows you to use properties in the Header of the token (such as
  12  // `kid`) to identify which key to use.
  13  //
  14  // The returned any may be a single key or a VerificationKeySet containing
  15  // multiple keys.
  16  type Keyfunc func(*Token) (any, error)
  17  
  18  // VerificationKey represents a public or secret key for verifying a token's signature.
  19  type VerificationKey interface {
  20  	crypto.PublicKey | []uint8
  21  }
  22  
  23  // VerificationKeySet is a set of public or secret keys. It is used by the parser to verify a token.
  24  type VerificationKeySet struct {
  25  	Keys []VerificationKey
  26  }
  27  
  28  // Token represents a JWT Token.  Different fields will be used depending on
  29  // whether you're creating or parsing/verifying a token.
  30  type Token struct {
  31  	Raw       string         // Raw contains the raw token.  Populated when you [Parse] a token
  32  	Method    SigningMethod  // Method is the signing method used or to be used
  33  	Header    map[string]any // Header is the first segment of the token in decoded form
  34  	Claims    Claims         // Claims is the second segment of the token in decoded form
  35  	Signature []byte         // Signature is the third segment of the token in decoded form.  Populated when you Parse a token
  36  	Valid     bool           // Valid specifies if the token is valid.  Populated when you Parse/Verify a token
  37  }
  38  
  39  // New creates a new [Token] with the specified signing method and an empty map
  40  // of claims. Additional options can be specified, but are currently unused.
  41  func New(method SigningMethod, opts ...TokenOption) *Token {
  42  	return NewWithClaims(method, MapClaims{}, opts...)
  43  }
  44  
  45  // NewWithClaims creates a new [Token] with the specified signing method and
  46  // claims. Additional options can be specified, but are currently unused.
  47  func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token {
  48  	return &Token{
  49  		Header: map[string]any{
  50  			"typ": "JWT",
  51  			"alg": method.Alg(),
  52  		},
  53  		Claims: claims,
  54  		Method: method,
  55  	}
  56  }
  57  
  58  // SignedString creates and returns a complete, signed JWT. The token is signed
  59  // using the SigningMethod specified in the token. Please refer to
  60  // https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types
  61  // for an overview of the different signing methods and their respective key
  62  // types.
  63  func (t *Token) SignedString(key any) (string, error) {
  64  	sstr, err := t.SigningString()
  65  	if err != nil {
  66  		return "", err
  67  	}
  68  
  69  	sig, err := t.Method.Sign(sstr, key)
  70  	if err != nil {
  71  		return "", err
  72  	}
  73  
  74  	return sstr + "." + t.EncodeSegment(sig), nil
  75  }
  76  
  77  // SigningString generates the signing string.  This is the most expensive part
  78  // of the whole deal. Unless you need this for something special, just go
  79  // straight for the SignedString.
  80  func (t *Token) SigningString() (string, error) {
  81  	h, err := json.Marshal(t.Header)
  82  	if err != nil {
  83  		return "", err
  84  	}
  85  
  86  	c, err := json.Marshal(t.Claims)
  87  	if err != nil {
  88  		return "", err
  89  	}
  90  
  91  	return t.EncodeSegment(h) + "." + t.EncodeSegment(c), nil
  92  }
  93  
  94  // EncodeSegment encodes a JWT specific base64url encoding with padding
  95  // stripped. In the future, this function might take into account a
  96  // [TokenOption]. Therefore, this function exists as a method of [Token], rather
  97  // than a global function.
  98  func (*Token) EncodeSegment(seg []byte) string {
  99  	return base64.RawURLEncoding.EncodeToString(seg)
 100  }
 101