diff --git a/request/extractor.go b/request/extractor.go index 1dbc59a6..57de8b77 100644 --- a/request/extractor.go +++ b/request/extractor.go @@ -3,6 +3,7 @@ package request import ( "errors" "net/http" + "strings" ) // Errors @@ -79,3 +80,18 @@ func (e *PostExtractionFilter) ExtractToken(req *http.Request) (string, error) { 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 +} diff --git a/request/extractor_test.go b/request/extractor_test.go index e3bbb0a3..5be2b5f3 100644 --- a/request/extractor_test.go +++ b/request/extractor_test.go @@ -89,3 +89,23 @@ func makeExampleRequest(method, path string, headers map[string]string, urlArgs } return r } + +func TestBearerExtractor(t *testing.T) { + request := makeExampleRequest("POST", "https://example.com/", map[string]string{"Authorization": "Bearer ToKen"}, nil) + token, err := BearerExtractor{}.ExtractToken(request) + if err != nil || token != "ToKen" { + t.Errorf("ExtractToken did not return token, returned: %v, %v", token, err) + } + + request = makeExampleRequest("POST", "https://example.com/", map[string]string{"Authorization": "Bearo ToKen"}, nil) + token, err = BearerExtractor{}.ExtractToken(request) + if err == nil || token != "" { + t.Errorf("ExtractToken did not return error, returned: %v, %v", token, err) + } + + request = makeExampleRequest("POST", "https://example.com/", map[string]string{"Authorization": "BeArEr HeLO"}, nil) + token, err = BearerExtractor{}.ExtractToken(request) + if err != nil || token != "HeLO" { + t.Errorf("ExtractToken did not return token, returned: %v, %v", token, err) + } +}