github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/auth/token/context.go (about)

     1  package token
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"strings"
     7  )
     8  
     9  // CtxKey defines a distinct type for context keys used by the access
    10  // package
    11  type CtxKey string
    12  
    13  // tokenCtxKey is the key for adding an access token to a context.Context
    14  const tokenCtxKey CtxKey = "Token"
    15  
    16  // AddToContext adds a token string to a context
    17  func AddToContext(ctx context.Context, s string) context.Context {
    18  	return context.WithValue(ctx, tokenCtxKey, s)
    19  }
    20  
    21  // FromCtx extracts the JWT from a given
    22  // context if one is set, returning nil otherwise
    23  func FromCtx(ctx context.Context) string {
    24  	iface := ctx.Value(tokenCtxKey)
    25  	if s, ok := iface.(string); ok {
    26  		return s
    27  	}
    28  	return ""
    29  }
    30  
    31  const (
    32  	// httpAuthorizationHeader is the http header field to check for tokens,
    33  	// follows OAuth 2.0 spec
    34  	httpAuthorizationHeader = "authorization"
    35  	// httpAuthorizationBearerPrefix is a prefix before a token in the
    36  	// Authorization header field. Follows OAuth 2.0 spec
    37  	httpAuthorizationBearerPrefix = "Bearer "
    38  )
    39  
    40  // OAuthTokenMiddleware parses any "authorization" header containing a Bearer
    41  // token & adds it to the request context
    42  func OAuthTokenMiddleware(next http.Handler) http.Handler {
    43  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    44  		reqToken := r.Header.Get(httpAuthorizationHeader)
    45  		if reqToken == "" && r.FormValue(httpAuthorizationHeader) != "" {
    46  			reqToken = r.FormValue(httpAuthorizationHeader)
    47  		}
    48  		if reqToken == "" {
    49  			next.ServeHTTP(w, r)
    50  			return
    51  		}
    52  
    53  		if !strings.HasPrefix(reqToken, httpAuthorizationBearerPrefix) {
    54  			next.ServeHTTP(w, r)
    55  			return
    56  		}
    57  
    58  		tokenStr := strings.TrimPrefix(reqToken, httpAuthorizationBearerPrefix)
    59  		ctx := AddToContext(r.Context(), tokenStr)
    60  
    61  		r = r.WithContext(ctx)
    62  		next.ServeHTTP(w, r)
    63  	})
    64  }
    65  
    66  // AddContextTokenToRequest checks the supplied context for an auth token and
    67  // adds it to an http request, returns true if a token is added
    68  func AddContextTokenToRequest(ctx context.Context, r *http.Request) (*http.Request, bool) {
    69  	if s := FromCtx(ctx); s != "" {
    70  		r.Header.Set(httpAuthorizationHeader, strings.Join([]string{httpAuthorizationBearerPrefix, s}, ""))
    71  		return r, true
    72  	}
    73  	return r, false
    74  }