package auth import ( "context" "net/http" "strings" "time" ) type tokenKey struct{} // BearerMiddleware validates the incoming bearer token as a Gitea PAT by // calling GET /api/v1/user. The validated token is stored in context for // downstream use by the Gitea client. func BearerMiddleware(giteaBaseURL string, next http.Handler) http.Handler { hc := &http.Client{Timeout: 5 * time.Second} return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token, ok := strings.CutPrefix(r.Header.Get("Authorization"), "Bearer ") if !ok || token == "" { http.Error(w, "unauthorized", http.StatusUnauthorized) return } req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, giteaBaseURL+"/api/v1/user", nil) if err != nil { http.Error(w, "unauthorized", http.StatusUnauthorized) return } req.Header.Set("Authorization", "token "+token) resp, err := hc.Do(req) if err != nil || resp.StatusCode != http.StatusOK { if resp != nil { _ = resp.Body.Close() } http.Error(w, "unauthorized", http.StatusUnauthorized) return } _ = resp.Body.Close() ctx := context.WithValue(r.Context(), tokenKey{}, token) next.ServeHTTP(w, r.WithContext(ctx)) }) } // TokenFromContext returns the validated Gitea PAT stored by BearerMiddleware. func TokenFromContext(ctx context.Context) string { if v, ok := ctx.Value(tokenKey{}).(string); ok { return v } return "" }