matrixcloud / api /middleware_auth.go
github-actions[bot]
Deploy from 4dfd54f2
857a91b
Raw
History Blame Contribute Delete
2.23 kB
package api
import (
"net/http"
"strings"
)
// alwaysOpen is the set of endpoints reachable without any credentials:
// liveness/readiness/version probes and the capabilities advert.
func alwaysOpen(path string) bool {
switch path {
case "/v1/health", "/v1/ready", "/v1/version", "/v1/capabilities":
return true
}
return false
}
// withAuth authenticates API requests. Two credential types are accepted and
// either is sufficient:
//
// - a valid user session bearer token (multitenant console), or
// - the operator API token (self-hosted single-tenant runtime), when one is
// configured via MATRIX_RUNTIME_API_TOKEN.
//
// Public probes, the user-auth endpoints, runtime onboarding (which carries its
// own join/runtime-token auth), and static console assets are always allowed.
// In production modes a request with no valid credential is rejected
// (fail-closed); in local-dev it is permitted for convenience.
func (s *Server) withAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
// Public probes + non-API (console assets).
if alwaysOpen(path) || !strings.HasPrefix(path, "/v1/") {
next.ServeHTTP(w, r)
return
}
// User auth endpoints (login/signup/forgot/reset/verify) and runtime
// onboarding (own-token auth) are always reachable.
if strings.HasPrefix(path, "/v1/auth/") ||
path == "/v1/cloud/runtimes/register" || path == "/v1/cloud/runtimes/heartbeat" {
next.ServeHTTP(w, r)
return
}
token := bearer(r)
// 1) Valid user session → allow (multitenant console).
if s.store != nil && token != "" {
if _, err := s.store.UserBySession(token); err == nil {
next.ServeHTTP(w, r)
return
}
}
// 2) Operator API token configured → require an exact match.
if s.cfg.APIToken != "" {
if token == s.cfg.APIToken {
next.ServeHTTP(w, r)
return
}
writeError(w, http.StatusUnauthorized, "missing or invalid bearer token")
return
}
// 3) No operator token configured: fail-closed in production, allow in dev.
if s.cfg.IsProduction() {
writeError(w, http.StatusUnauthorized, "authentication required")
return
}
next.ServeHTTP(w, r)
})
}