github.com/lestrrat-go/jwx/v2@v2.0.21/jwt/http.go (about) 1 package jwt 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/url" 7 "strconv" 8 "strings" 9 10 "github.com/lestrrat-go/jwx/v2/internal/pool" 11 ) 12 13 // ParseHeader parses a JWT stored in a http.Header. 14 // 15 // For the header "Authorization", it will strip the prefix "Bearer " and will 16 // treat the remaining value as a JWT. 17 func ParseHeader(hdr http.Header, name string, options ...ParseOption) (Token, error) { 18 key := http.CanonicalHeaderKey(name) 19 v := strings.TrimSpace(hdr.Get(key)) 20 if v == "" { 21 return nil, fmt.Errorf(`empty header (%s)`, key) 22 } 23 24 if key == "Authorization" { 25 // Authorization header is an exception. We strip the "Bearer " from 26 // the prefix 27 v = strings.TrimSpace(strings.TrimPrefix(v, "Bearer")) 28 } 29 30 return ParseString(v, options...) 31 } 32 33 // ParseForm parses a JWT stored in a url.Value. 34 func ParseForm(values url.Values, name string, options ...ParseOption) (Token, error) { 35 v := strings.TrimSpace(values.Get(name)) 36 if v == "" { 37 return nil, fmt.Errorf(`empty value (%s)`, name) 38 } 39 40 return ParseString(v, options...) 41 } 42 43 // ParseRequest searches a http.Request object for a JWT token. 44 // 45 // Specifying WithHeaderKey() will tell it to search under a specific 46 // header key. Specifying WithFormKey() will tell it to search under 47 // a specific form field. 48 // 49 // By default, "Authorization" header will be searched. 50 // 51 // If WithHeaderKey() is used, you must explicitly re-enable searching for "Authorization" header. 52 // 53 // # searches for "Authorization" 54 // jwt.ParseRequest(req) 55 // 56 // # searches for "x-my-token" ONLY. 57 // jwt.ParseRequest(req, jwt.WithHeaderKey("x-my-token")) 58 // 59 // # searches for "Authorization" AND "x-my-token" 60 // jwt.ParseRequest(req, jwt.WithHeaderKey("Authorization"), jwt.WithHeaderKey("x-my-token")) 61 func ParseRequest(req *http.Request, options ...ParseOption) (Token, error) { 62 var hdrkeys []string 63 var formkeys []string 64 var parseOptions []ParseOption 65 for _, option := range options { 66 //nolint:forcetypeassert 67 switch option.Ident() { 68 case identHeaderKey{}: 69 hdrkeys = append(hdrkeys, option.Value().(string)) 70 case identFormKey{}: 71 formkeys = append(formkeys, option.Value().(string)) 72 default: 73 parseOptions = append(parseOptions, option) 74 } 75 } 76 if len(hdrkeys) == 0 { 77 hdrkeys = append(hdrkeys, "Authorization") 78 } 79 80 mhdrs := pool.GetKeyToErrorMap() 81 defer pool.ReleaseKeyToErrorMap(mhdrs) 82 mfrms := pool.GetKeyToErrorMap() 83 defer pool.ReleaseKeyToErrorMap(mfrms) 84 85 for _, hdrkey := range hdrkeys { 86 // Check presence via a direct map lookup 87 if _, ok := req.Header[http.CanonicalHeaderKey(hdrkey)]; !ok { 88 // if non-existent, not error 89 continue 90 } 91 92 tok, err := ParseHeader(req.Header, hdrkey, parseOptions...) 93 if err != nil { 94 mhdrs[hdrkey] = err 95 continue 96 } 97 return tok, nil 98 } 99 100 if cl := req.ContentLength; cl > 0 { 101 if err := req.ParseForm(); err != nil { 102 return nil, fmt.Errorf(`failed to parse form: %w`, err) 103 } 104 } 105 106 for _, formkey := range formkeys { 107 // Check presence via a direct map lookup 108 if _, ok := req.Form[formkey]; !ok { 109 // if non-existent, not error 110 continue 111 } 112 113 tok, err := ParseForm(req.Form, formkey, parseOptions...) 114 if err != nil { 115 mfrms[formkey] = err 116 continue 117 } 118 return tok, nil 119 } 120 121 // Everything below is a preulde to error reporting. 122 var triedHdrs strings.Builder 123 for i, hdrkey := range hdrkeys { 124 if i > 0 { 125 triedHdrs.WriteString(", ") 126 } 127 triedHdrs.WriteString(strconv.Quote(hdrkey)) 128 } 129 130 var triedForms strings.Builder 131 for i, formkey := range formkeys { 132 if i > 0 { 133 triedForms.WriteString(", ") 134 } 135 triedForms.WriteString(strconv.Quote(formkey)) 136 } 137 138 var b strings.Builder 139 b.WriteString(`failed to find a valid token in any location of the request (tried: [header keys: `) 140 b.WriteString(triedHdrs.String()) 141 b.WriteByte(']') 142 if triedForms.Len() > 0 { 143 b.WriteString(", form keys: [") 144 b.WriteString(triedForms.String()) 145 b.WriteByte(']') 146 } 147 b.WriteByte(')') 148 149 lmhdrs := len(mhdrs) 150 lmfrms := len(mfrms) 151 if lmhdrs > 0 || lmfrms > 0 { 152 b.WriteString(". Additionally, errors were encountered during attempts to parse") 153 154 if lmhdrs > 0 { 155 b.WriteString(" headers: (") 156 count := 0 157 for hdrkey, err := range mhdrs { 158 if count > 0 { 159 b.WriteString(", ") 160 } 161 b.WriteString("[header key: ") 162 b.WriteString(strconv.Quote(hdrkey)) 163 b.WriteString(", error: ") 164 b.WriteString(strconv.Quote(err.Error())) 165 b.WriteString("]") 166 count++ 167 } 168 b.WriteString(")") 169 } 170 171 if lmfrms > 0 { 172 count := 0 173 b.WriteString(" forms: (") 174 for formkey, err := range mfrms { 175 if count > 0 { 176 b.WriteString(", ") 177 } 178 b.WriteString("[form key: ") 179 b.WriteString(strconv.Quote(formkey)) 180 b.WriteString(", error: ") 181 b.WriteString(strconv.Quote(err.Error())) 182 b.WriteString("]") 183 count++ 184 } 185 } 186 } 187 return nil, fmt.Errorf(b.String()) 188 }