feat: initial mcp-chassis with auth primitives
Shared Go library for Mathias-owned MCP servers, born from spike S3 of the 2026-05 homelab architecture review (see gitea.d-ma.be/mathias/infra/docs/superpowers/handoffs/2026-05-22-mcp-chassis-spike.md for the viability assessment and abort-criterion check). Provides three primitives every MCP server today re-implements: - auth.JWTValidator — Dex OIDC JWT validation. nil-safe (nil = "JWT disabled"), audience-optional. Lifted from the identical ~80-LOC implementations in gitea-mcp and hyperguild/ingestion. - auth.BearerMiddleware — dual-mode static-Bearer-or-Dex-JWT gate. Static wins first to avoid emitting a WWW-Authenticate challenge that would flip claude.ai's MCP client into OAuth discovery for static-only deployments. The fall-through 401 emits the RFC 9728 resource_metadata header only when explicitly configured. - auth.ProtectedResourceHandler — RFC 9728 /.well-known/oauth-protected-resource metadata document handler. Test coverage exercises every branch (static OK, JWT-disabled, empty bearer, wrong static, with-challenge vs without-challenge, nil-validator-Validate). go test -race clean. Deps: github.com/lestrrat-go/jwx/v2 (already a dep of every consumer) and testify (test-only). No new transitive deps. First migration target: gitea-mcp. If that port lands in one PR (abort criterion from spec), brain-mcp (ingestion) follows. Otherwise chassis reverts per the spec. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
33
auth/protected_resource_test.go
Normal file
33
auth/protected_resource_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestProtectedResourceHandler(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
h := ProtectedResourceHandler(
|
||||
"https://brain-mcp.d-ma.be",
|
||||
"https://auth.d-ma.be",
|
||||
)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/.well-known/oauth-protected-resource", nil))
|
||||
|
||||
require.Equal(t, http.StatusOK, rec.Code)
|
||||
require.Equal(t, "application/json", rec.Header().Get("Content-Type"))
|
||||
|
||||
var got struct {
|
||||
Resource string `json:"resource"`
|
||||
AuthorizationServers []string `json:"authorization_servers"`
|
||||
}
|
||||
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &got))
|
||||
require.Equal(t, "https://brain-mcp.d-ma.be", got.Resource)
|
||||
require.Equal(t, []string{"https://auth.d-ma.be"}, got.AuthorizationServers)
|
||||
}
|
||||
Reference in New Issue
Block a user