auth/jwt.go
func TokenGenerator(h http.Handler, auth Authenticator, secret []byte, opts ...TokenOpt) http.Handler {
	o := options{
		logger:     handler.NopLogger(),
		claimer:    func(c *jwt.StandardClaims) jwt.Claims { return c },
		expiration: time.Hour * 24 * 15,
		user:       "user",
		password:   "password",
	}

	o.apply(opts)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var err error
		if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
			err = r.ParseMultipartForm(0)
		} else {
			err = r.ParseForm()
		}
		if err != nil {
			o.logger.Print("Invalid request form: ", err)

			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		user := r.FormValue(o.user)
		password := r.FormValue(o.password)
		if user == "" || password == "" || !auth.Authenticate(user, password) {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		expiration := time.Now().Add(o.expiration)
		t := jwt.NewWithClaims(jwt.SigningMethodHS512, o.claimer(&jwt.StandardClaims{
			Subject:   user,
			ExpiresAt: expiration.Unix(),
			Issuer:    o.issuer,
		}))

		if token, err := t.SignedString(secret); err == nil {
			if h == nil {
				w.Header().Add("Authorization", "Bearer "+token)
				w.Write([]byte(token))

				return
			}

			r = r.WithContext(context.WithValue(r.Context(), TokenKey, token))

			h.ServeHTTP(w, r)
		} else {
			o.logger.Print("Error authenticating user:", err)

			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	})
}
func TokenGenerator(h http.Handler, auth Authenticator, secret []byte, opts ...TokenOpt) http.Handler {
	o := options{
		logger:     handler.NopLogger(),
		claimer:    func(c *jwt.StandardClaims) jwt.Claims { return c },
		expiration: time.Hour * 24 * 15,
		user:       "user",
		password:   "password",
	}

	o.apply(opts)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var err error
		if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
			err = r.ParseMultipartForm(0)
		} else {
			err = r.ParseForm()
		}
		if err != nil {
			o.logger.Print("Invalid request form: ", err)

			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		user := r.FormValue(o.user)
		password := r.FormValue(o.password)
		if user == "" || password == "" || !auth.Authenticate(user, password) {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		expiration := time.Now().Add(o.expiration)
		t := jwt.NewWithClaims(jwt.SigningMethodHS512, o.claimer(&jwt.StandardClaims{
			Subject:   user,
			ExpiresAt: expiration.Unix(),
			Issuer:    o.issuer,
		}))

		if token, err := t.SignedString(secret); err == nil {
			if h == nil {
				w.Header().Add("Authorization", "Bearer "+token)
				w.Write([]byte(token))

				return
			}

			r = r.WithContext(context.WithValue(r.Context(), TokenKey, token))

			h.ServeHTTP(w, r)
		} else {
			o.logger.Print("Error authenticating user:", err)

			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	})
}
// TokenGenerator returns a handler that will read a username and password from
// a request form, create a jwt token if they are valid, and store the signed
// token in the request context for later consumption.
//
// If handler h is nil, the generated token will be written verbatim in the
// response.