initial commit

This commit is contained in:
Daniel Noulet 2026-10-07 15:14:50 +02:00
commit 1253955070
75 changed files with 13972 additions and 0 deletions

View file

@ -0,0 +1,63 @@
package auth
import (
"context"
"errors"
"net/http"
)
type ctxKey struct{}
// WithUser stores the verified identity on the request context.
func WithUser(ctx context.Context, u User) context.Context {
return context.WithValue(ctx, ctxKey{}, u)
}
// FromContext returns the identity attached by the middleware.
func FromContext(ctx context.Context) (User, bool) {
u, ok := ctx.Value(ctxKey{}).(User)
return u, ok
}
// Middleware verifies the Authorization header and rejects requests that carry
// no usable credential.
type Middleware struct {
verifier Verifier
}
// NewMiddleware returns middleware backed by the verifier.
func NewMiddleware(v Verifier) *Middleware {
return &Middleware{verifier: v}
}
// Wrap protects h, making the verified identity available to it.
func (m *Middleware) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token, err := BearerToken(r.Header.Get("Authorization"))
if err != nil {
unauthorized(w, err)
return
}
user, err := m.verifier.Verify(r.Context(), token)
if err != nil {
unauthorized(w, err)
return
}
next.ServeHTTP(w, r.WithContext(WithUser(r.Context(), user)))
})
}
// WrapFunc protects a handler function.
func (m *Middleware) WrapFunc(next http.HandlerFunc) http.HandlerFunc {
return m.Wrap(next).ServeHTTP
}
func unauthorized(w http.ResponseWriter, err error) {
w.Header().Set("WWW-Authenticate", `Bearer realm="go-places"`)
// The response deliberately does not echo the reason.
if errors.Is(err, ErrMissingToken) {
http.Error(w, "unauthorized: a bearer token is required", http.StatusUnauthorized)
return
}
http.Error(w, "unauthorized: the token was rejected", http.StatusUnauthorized)
}