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 interface{} may be a single key or a VerificationKeySet containing 15 // multiple keys. 16 type Keyfunc func(*Token) (interface{}, 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]interface{} // 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]interface{}{ 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 interface{}) (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