Skip to content

Add auth, security headers & a gateway

The transport servers are composed from small building blocks: authentication and security-header middleware from transport/http (and AuthInterceptor from transport/grpc), stitched together with a go/transit Chain, plus an optional grpc-gateway.

Authenticate HTTP requests

AuthMiddleware verifies each request against a go/authn verifier and stores the identity in the request context. It is an ordinary transit Middleware, so it composes into a Chain:

import (
    "gitlab.com/phpboyscout/go/authn"
    transithttp "gitlab.com/phpboyscout/go/transit/http"
    transporthttp "gitlab.com/phpboyscout/go/transport/http"
)

auth, err := transporthttp.AuthMiddleware(
    transporthttp.WithBearerVerifier(jwtVerifier),   // authn.Verifier
    transporthttp.WithAuthLogger(log),
)
if err != nil {
    return err
}

chain := transithttp.NewChain(auth, transporthttp.SecurityHeadersMiddleware())
srv, _ := transporthttp.Register(ctx, "api", controller, log, settings, pair, handler,
    transporthttp.WithMiddleware(chain))

On failure it writes a generic 401/403 with the credential redacted from logs. Read the verified identity downstream with transporthttp.IdentityFromContext(ctx).

Add security headers

SecurityHeadersMiddleware sets a secure baseline (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and optionally HSTS/CSP). Tune it with options:

sec := transporthttp.SecurityHeadersMiddleware(
    transporthttp.WithHSTS(365*24*time.Hour, true, true),
    transporthttp.WithContentSecurityPolicy("default-src 'self'"),
    transporthttp.WithFrameOptions("DENY"),
)

Authenticate gRPC calls

transport/grpc mirrors the HTTP auth surface as an interceptor:

import transportgrpc "gitlab.com/phpboyscout/go/transport/grpc"

ic, err := transportgrpc.AuthInterceptor(
    transportgrpc.WithGRPCBearerVerifier(jwtVerifier),
    transportgrpc.WithGRPCMethodSkipper(func(m string) bool { return m == "/grpc.health.v1.Health/Check" }),
)
srv, _ := transportgrpc.NewServer(settings, transportgrpc.WithInterceptors(
    transitgrpc.NewInterceptorChain(ic),
))

Expose a gRPC service over REST with the gateway

transport/gateway wraps a gRPC connection in a grpc-gateway http.Handler. Give it a connection (dial the gRPC server with go/grpcclient or transport/grpc.DialLocal) and your generated registration function:

import transportgateway "gitlab.com/phpboyscout/go/transport/gateway"

conn, _ := transportgrpc.DialLocal(grpcSettings, grpcPair)
handler, err := transportgateway.New(ctx, conn,
    func(ctx context.Context, mux *runtime.ServeMux, c *grpc.ClientConn) error {
        return widgetv1.RegisterWidgetServiceHandler(ctx, mux, c)
    },
    transportgateway.WithMiddleware(chain), // optional transit Chain over the REST handler
)

The gateway handler is a plain http.Handler, so serve it through transport/http like any other — the whole stack composes.