diff --git a/request/doc.go b/request/doc.go new file mode 100644 index 0000000..c01069c --- /dev/null +++ b/request/doc.go @@ -0,0 +1,7 @@ +// Utility package for extracting JWT tokens from +// HTTP requests. +// +// The main function is ParseFromRequest and it's WithClaims variant. +// See examples for how to use the various Extractor implementations +// or roll your own. +package request diff --git a/request/extractor.go b/request/extractor.go index 57ea2dd..61c330a 100644 --- a/request/extractor.go +++ b/request/extractor.go @@ -10,12 +10,15 @@ var ( ErrNoTokenInRequest = errors.New("no token present in request") ) -// Interface for extracting a token from an HTTP request +// 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) } -// Extract token from headers +// 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) { @@ -28,7 +31,8 @@ func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) { return "", ErrNoTokenInRequest } -// Extract token from request args +// Extract token from request arguments. This includes a POSTed form or +// GET URL arguments. Argument names are tried in order until there's a match. type ArgumentExtractor []string func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) { @@ -45,7 +49,7 @@ func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) { return "", ErrNoTokenInRequest } -// Tries extractors in order until one works or an error occurs +// 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) { @@ -60,7 +64,8 @@ func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) { return "", ErrNoTokenInRequest } -// Wrap an Extractor in this to post-process the value before it's handed off +// Wrap 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) diff --git a/request/oauth2.go b/request/oauth2.go index bbb6ac2..0f7fa02 100644 --- a/request/oauth2.go +++ b/request/oauth2.go @@ -4,7 +4,8 @@ import ( "strings" ) -// Extract Authorization header and strip 'Bearer ' from it +// Extract bearer token from Authorization header +// Uses PostExtractionFilter to strip "Bearer " prefix from header var AuthorizationHeaderExtractor = &PostExtractionFilter{ HeaderExtractor{"Authorization"}, func(tok string) (string, error) { @@ -16,7 +17,8 @@ var AuthorizationHeaderExtractor = &PostExtractionFilter{ }, } -// Extractor for OAuth2 access tokens +// Extractor for OAuth2 access tokens. Looks in 'Authorization' +// header then 'access_token' argument for a token. var OAuth2Extractor = &MultiExtractor{ // Look for authorization token first AuthorizationHeaderExtractor, diff --git a/request/request.go b/request/request.go index 9daaa48..1807b39 100644 --- a/request/request.go +++ b/request/request.go @@ -5,20 +5,20 @@ import ( "net/http" ) -// Try to find the token in an http.Request. -// This method will call ParseMultipartForm if there's no token in the header. -// Currently, it looks in the Authorization header as well as -// looking for an 'access_token' request parameter in req.Form. +// Extract and parse a JWT token from an HTTP request. +// This behaves the same as Parse, but accepts a request and an extractor +// instead of a token string. The Extractor interface allows you to define +// the logic for extracting a token. Several useful implementations are provided. func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jwt.Keyfunc) (token *jwt.Token, err error) { return ParseFromRequestWithClaims(req, extractor, jwt.MapClaims{}, keyFunc) } +// ParseFromRequest but with custom Claims type func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, claims jwt.Claims, keyFunc jwt.Keyfunc) (token *jwt.Token, err error) { // Extract token from request - tokStr, err := extractor.ExtractToken(req) - if err != nil { + if tokStr, err := extractor.ExtractToken(req); err == nil { + return jwt.ParseWithClaims(tokStr, claims, keyFunc) + } else { return nil, err } - - return jwt.ParseWithClaims(tokStr, claims, keyFunc) }