package auth import ( "crypto/subtle" "net/http" "strings" ) // BearerMiddleware authenticates requests via the Authorization header. // // A request is allowed when: // // 1. The Bearer token is a valid JWT issued by the configured Dex OIDC server, or // 2. The Bearer token matches staticToken (constant-time compare). // // Any other case — including missing or empty Authorization header — returns 401. // // The Gitea service PAT is intentionally NOT used to authenticate the caller: // it is only used by the Gitea client for upstream API calls. Decoupling the // two prevents the MCP endpoint from being reachable anonymously when a service // PAT happens to be configured. func BearerMiddleware(jwtValidator *JWTValidator, staticToken string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { bearer, hasBearer := strings.CutPrefix(r.Header.Get("Authorization"), "Bearer ") if !hasBearer || bearer == "" { http.Error(w, "unauthorized", http.StatusUnauthorized) return } if jwtValidator.Validate(r.Context(), bearer) { next.ServeHTTP(w, r) return } if staticToken != "" && subtle.ConstantTimeCompare([]byte(bearer), []byte(staticToken)) == 1 { next.ServeHTTP(w, r) return } http.Error(w, "unauthorized", http.StatusUnauthorized) }) }