DocsHTTP ServerAuth middleware

Auth middleware

Extract a Bearer token into request context and read the caller's identity in handlers.

AuthMiddleware pulls the Bearer token off a request, runs your extractor to turn it into claims, and injects the caller's identity into the request context. A handler downstream reads that identity back without re-parsing anything.

Extracting claims

You supply a ClaimsExtractor, a function that parses a raw token into Claims. The middleware handles the transport, so your function only decides whether a token is valid and what identity it carries. Return an error to reject the request with a 401.

extract := func(token string) (*server.Claims, error) {
	// verify the token however your system does, then return the identity.
	return &server.Claims{
		OrgID:  "org-1",
		UserID: "user-1",
		Scopes: []string{"read", "write"},
	}, nil
}

r.Use(server.AuthMiddleware(extract, logger))

A missing or malformed Authorization header, or an extractor that returns an error or nil claims, aborts the request with a 401 before the handler runs.

Reading identity in a handler

The middleware stores the org ID, user ID, and scopes on the request context. Read them back with the FromContext helpers.

func handler(w http.ResponseWriter, r *http.Request) {
	org, _ := server.OrgIDFromContext(r.Context())
	user, _ := server.UserIDFromContext(r.Context())
	scopes := server.ScopesFromContext(r.Context())
	// ... authorize using org, user, and scopes
}

Each FromContext reader returns an ok boolean (except ScopesFromContext, which returns nil when unset), so a handler can tell an absent value apart from an empty one.

Setting identity yourself

The ContextWith helpers put those same values on a context directly, which is how a test or an alternate auth path seeds identity without going through the middleware.

ctx := server.ContextWithOrgID(r.Context(), "org-1")
ctx = server.ContextWithUserID(ctx, "user-1")

Authorizing an operation

Identity answers who the caller is. To decide whether they may perform an operation, implement Authorizer and check it before a privileged action. It is called with an Action (one of ActionRead, ActionWrite, ActionDelete, ActionAdmin) and an optional resource ID, and returns ErrUnauthorized to deny.

if err := authz.Authorize(r.Context(), server.ActionWrite, itemID); err != nil {
	server.WriteError(w, http.StatusForbidden, err)
	return
}

Note

Authorize reads identity from the context the middleware populated, so an authorizer stays decoupled from how the token was parsed.