libauth/chiauth/chiauth.go

91 lines
2.4 KiB
Go

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 <Token>'"
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
}