Help us shape the future of Go! Take the 2026 Go Developer Survey

ginadapter

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package ginadapter integrates the module with gin and the wide-event logger: it runs the net/http middleware of the providers in a gin chain, registers their routes on a gin router, gates routes with authorization checks, and records authentication outcomes on the request's wide event.

It is the only package of the library that imports gin and go-wide-event-logger. It records on the wide event the wideevent.Middleware put into the request context and never emits one of its own; it records IDs and decisions, never usernames, emails, names, tokens or codes. Mount the wide-event middleware with RedactQuery, or the code and state of every OAuth callback reach your logs. Everything in it is safe for concurrent use.

Example
package main

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/gin-gonic/gin"
	wideevent "github.com/mxcd/go-wide-event-logger"

	"github.com/govengers/auth"
	"github.com/govengers/auth/authorization"
	"github.com/govengers/auth/ginadapter"
)

func main() {
	// requireAPI stands in for session.Guard.RequireAPI: it authenticates the request from its session.
	requireAPI := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
			identity := &auth.Identity{Provider: "password", Subject: request.Header.Get("X-Example-User"), Active: true}
			if identity.Subject == "admin-1" {
				identity.Roles = []string{auth.RoleAdmin}
			}
			next.ServeHTTP(writer, request.WithContext(auth.WithIdentity(request.Context(), identity)))
		})
	}

	engine := gin.New()
	engine.Use(wideevent.Middleware(wideevent.WithEmitter(wideevent.EmitterFunc(func(*wideevent.Event) {}))))
	api := engine.Group("/api", ginadapter.Middleware(requireAPI))
	api.GET("/reports", ginadapter.Require(authorization.IsAdmin()), func(ginContext *gin.Context) {
		ginContext.String(http.StatusOK, "reports")
	})

	for _, subject := range []string{"admin-1", "user-7"} {
		request := httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/api/reports", nil)
		request.Header.Set("X-Example-User", subject)
		recorder := httptest.NewRecorder()
		engine.ServeHTTP(recorder, request)
		fmt.Println(subject, recorder.Code)
	}
}
Output:
admin-1 200
user-7 403

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Middleware

func Middleware(middleware func(http.Handler) http.Handler) gin.HandlerFunc

Middleware runs net/http middleware in a gin chain: when it calls its next handler, ginContext.Request becomes the (possibly enriched) request and the rest of the chain runs inside it; otherwise the chain is aborted. Like a net/http chain it wraps once, here, so state the middleware keeps across requests survives. Each request finds its gin chain through its context: a middleware that passes on a request whose context does not derive from the one it got is answered 500. Gin handlers keep writing to ginContext.Writer, so a writer the middleware wraps for its next handler is not seen.

func Observe

func Observe(ctx context.Context, outcome auth.Outcome)

Observe is an auth.Observer that records the outcome on the request's wide event: auth.provider, auth.action, auth.result, the client code, reason and error of Err, degraded for a success with Err, the subject and user ID of the identity (the impersonator's subject and the impersonated subject while impersonating), and the request outcome when the outcome decided it. A session.Guard reports a refresh on the same event before the request's authenticate outcome, so a refresh outcome goes under auth.refresh.* instead, without the user ID: no key is set twice. For the same reason a session.Impersonator's outcome, which follows the Guard's, goes under auth.impersonation.*. Without a wide event in ctx it does nothing.

func RedactQuery

func RedactQuery(we *wideevent.Event, ginContext *gin.Context)

RedactQuery is a wide-event pre-enricher: mount it with wideevent.Middleware(wideevent.WithPreEnricher(ginadapter.RedactQuery)), or the code and state of every OAuth callback reach your logs. The middleware records the raw query as request.query; RedactQuery sets it again with every parameter name kept and every value replaced by "redacted", cut to 512 bytes. The JSON emitters print the latest value of a key; the dev emitters print every value, the raw query included, so keep those to development or emit only the latest values. Call it first from your own pre-enricher when you need one.

func RegisterRoutes

func RegisterRoutes(router gin.IRoutes, routes []auth.Route)

RegisterRoutes registers each route with router.Handle(route.Method, route.Path, gin.WrapH(route.Handler)), so gin route templates (and therefore metric labels) are the provider paths. Register on the engine root. Like gin it panics on a path that conflicts with one already registered, which is a wiring mistake at startup.

func Require

func Require(check authorization.Check) gin.HandlerFunc

Require runs check against the request context: allowed continues; refused aborts with auth.ResponseFor (401/403/500) and records authorization.denied / authorization.reason / authorization.error and we.Failure(err). A nil check is a wiring mistake: every request is answered 500.

func RequireMethodPermission

func RequireMethodPermission(resource string) gin.HandlerFunc

RequireMethodPermission is Require(authorization.HasPermission(resource, auth.AccessForMethod(method))) evaluated per request: one gate for a route group where GET, HEAD and OPTIONS need read access on resource and every other method write access. Same recording and responses as Require.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL