package chiauth import ( "context" "net/http" "strings" "git.rootprojects.org/root/keypairs/keyfetch" "git.rootprojects.org/root/libauth" ) type ctxKey string // JWSKey is used to get the InspectableToken from http.Request.Context().Value(chiauth.JWSKey) var JWSKey = ctxKey("jws") // VerificationParams specify the Issuer and whether or not the token is Optional (if provided, it must pass verification) type VerificationParams struct { Issuers keyfetch.Whitelist Optional bool /* ExpLeeway int NbfLeeway int SelfSigned bool PubKey keypairs.PublicKey */ } // NewTokenVerifier returns a token-verifying middleware // // tokenVerifier := chiauth.NewTokenVerifier(chiauth.VerificationParams{ // Issuers: keyfetch.Whitelist([]string{"https://accounts.google.com"}), // Optional: false, // }) // r.Use(tokenVerifier) // // r.Post("/api/users/profile", func(w http.ResponseWriter, r *http.Request) { // ctx := r.Context() // jws, ok := ctx.Value(chiauth.JWSKey).(*libauth.JWS) // }) func NewTokenVerifier(opts VerificationParams) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // just setting a default, other handlers can change this token := r.Header.Get("Authorization") if token == "" { if opts.Optional { next.ServeHTTP(w, r) return } errmsg := "bad format: missing 'Authorization' header and 'access_token' query" http.Error(w, errmsg, http.StatusBadRequest) return } parts := strings.Split(token, " ") if len(parts) != 2 { errmsg := "bad format: expected 'Authorization' header to be in the format of 'Bearer '" http.Error(w, errmsg, http.StatusBadRequest) return } token = parts[1] inspected, err := libauth.VerifyJWT(token, opts.Issuers, r) if nil != err { errmsg := "invalid token: " + err.Error() http.Error(w, errmsg, http.StatusBadRequest) return } if !inspected.Trusted { errmsg := "invalid token: bad signature" http.Error(w, errmsg, http.StatusBadRequest) return } ctx := context.WithValue(r.Context(), JWSKey, inspected) next.ServeHTTP(w, r.WithContext(ctx)) }) } } // GetJWS retrieves *libauth.JWS from r.Context() func GetJWS(r *http.Request) *libauth.JWS { ctx := r.Context() jws, _ := ctx.Value(JWSKey).(*libauth.JWS) return jws }