---
title: "Protect a Go net/http Service"
url: "https://docs.caracal.run/guides/protect-nethttp/"
markdown_url: "https://docs.caracal.run/markdown/guides/protect-nethttp.md"
description: "Wrap Go HTTP handlers with the mcp-nethttp middleware to verify mandates and attach claims to context.Context."
page_type: "page"
concepts: []
requires: []
---

# Protect a Go net/http Service

Canonical URL: https://docs.caracal.run/guides/protect-nethttp/
Markdown URL: https://docs.caracal.run/markdown/guides/protect-nethttp.md
Description: Wrap Go HTTP handlers with the mcp-nethttp middleware to verify mandates and attach claims to context.Context.
Page type: page
Concepts: none
Requires: none

---

Use the Go net/http connector when a Go service should verify Caracal mandates at the handler boundary.

## Install

```bash
go get github.com/garudex-labs/caracal/packages/connectors/nethttp/go
go get github.com/garudex-labs/caracal/packages/revocation/go
```

## Wrap a handler

```go
package main

import (
	"encoding/json"
	"net/http"
	"time"

	mcpnethttp "github.com/garudex-labs/caracal/packages/connectors/nethttp/go"
	revocation "github.com/garudex-labs/caracal/packages/revocation/go"
	transportmcp "github.com/garudex-labs/caracal/packages/transport/mcp/go"
)

func main() {
	revocations := revocation.NewInMemoryStore(24 * time.Hour)

	verifier := transportmcp.NewVerifier(transportmcp.Options{
		Issuer:      "https://sts.example.com",
		Audience:    "https://api.example.com",
		ZoneID:      "zone_prod",
		Revocations: revocations,
	})

	protected := mcpnethttp.VerifierMiddleware(verifier.Require(transportmcp.Options{
		RequiredScopes:  []string{"tickets:read"},
		RequiredTargets: []string{"https://api.example.com/tickets"},
	}))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		claims, ok := mcpnethttp.ClaimsFromContext(r.Context())
		if !ok {
			http.Error(w, "missing claims", http.StatusUnauthorized)
			return
		}
		_ = json.NewEncoder(w).Encode(map[string]string{"subject": claims.Sub})
	}))

	http.Handle("/tickets", protected)
	_ = http.ListenAndServe(":8080", nil)
}
```

## Enforce constraints

| Option | Use it for |
| --- | --- |
| `RequiredScopes` | Route or operation permission. |
| `RequiredTargets` | Resource target matching. |
| `RequireAgent` | Agent-only endpoints. |
| `RequireDelegation` | Delegated-only endpoints. |
| `RequireChainContains` | Application path requirements. |
| `MaxHopCount` | Delegation depth limit. |

## Production revocation

The in-memory store does not share revocations across instances. Use the Redis revocation connector and consume `caracal.sessions.revoke` for production resource servers.

## Validate

1. Call without a bearer token and expect `401`.
2. Call with a valid mandate and expect the handler response.
3. Remove a required scope and expect `403`.
4. Mark the session revoked and expect `session_revoked`.

Related pages: [Mandates](/concepts/mandate/) and [Sessions and Revocation](/concepts/sessions-revocation/).
