12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- package request
- import (
- "errors"
- "net/http"
- "strings"
- )
- // Errors
- var (
- ErrNoTokenInRequest = errors.New("no token present in request")
- )
- // Extractor is an interface for extracting a token from an HTTP request.
- // The ExtractToken method should return a token string or an error.
- // If no token is present, you must return ErrNoTokenInRequest.
- type Extractor interface {
- ExtractToken(*http.Request) (string, error)
- }
- // HeaderExtractor is an extractor for finding a token in a header.
- // Looks at each specified header in order until there's a match
- type HeaderExtractor []string
- func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
- // loop over header names and return the first one that contains data
- for _, header := range e {
- if ah := req.Header.Get(header); ah != "" {
- return ah, nil
- }
- }
- return "", ErrNoTokenInRequest
- }
- // ArgumentExtractor extracts a token from request arguments. This includes a POSTed form or
- // GET URL arguments. Argument names are tried in order until there's a match.
- // This extractor calls `ParseMultipartForm` on the request
- type ArgumentExtractor []string
- func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) {
- // Make sure form is parsed
- req.ParseMultipartForm(10e6)
- // loop over arg names and return the first one that contains data
- for _, arg := range e {
- if ah := req.Form.Get(arg); ah != "" {
- return ah, nil
- }
- }
- return "", ErrNoTokenInRequest
- }
- // MultiExtractor tries Extractors in order until one returns a token string or an error occurs
- type MultiExtractor []Extractor
- func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
- // loop over header names and return the first one that contains data
- for _, extractor := range e {
- if tok, err := extractor.ExtractToken(req); tok != "" {
- return tok, nil
- } else if !errors.Is(err, ErrNoTokenInRequest) {
- return "", err
- }
- }
- return "", ErrNoTokenInRequest
- }
- // PostExtractionFilter wraps an Extractor in this to post-process the value before it's handed off.
- // See AuthorizationHeaderExtractor for an example
- type PostExtractionFilter struct {
- Extractor
- Filter func(string) (string, error)
- }
- func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string, error) {
- if tok, err := e.Extractor.ExtractToken(req); tok != "" {
- return e.Filter(tok)
- } else {
- return "", err
- }
- }
- // BearerExtractor extracts a token from the Authorization header.
- // The header is expected to match the format "Bearer XX", where "XX" is the
- // JWT token.
- type BearerExtractor struct{}
- func (e BearerExtractor) ExtractToken(req *http.Request) (string, error) {
- tokenHeader := req.Header.Get("Authorization")
- // The usual convention is for "Bearer" to be title-cased. However, there's no
- // strict rule around this, and it's best to follow the robustness principle here.
- if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), "bearer ") {
- return "", ErrNoTokenInRequest
- }
- return tokenHeader[7:], nil
- }
|