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

ginadapter

package
v1.2.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: 8 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 wide-event-logger. It records on the wide event the wide-event middleware (wide-event-logger's ginadapter.NewMiddleware) put into the request context and never emits one of its own; it records IDs and decisions, never usernames, emails, names, tokens or codes. That middleware redacts every query value itself, so the code and state of OAuth callbacks stay out of 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/govengers/wide-event-logger"

	wideeventgin "github.com/govengers/wide-event-logger/ginadapter"

	"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)))
		})
	}

	wideEvents, err := wideeventgin.NewMiddleware(&wideeventgin.Options{Emitter: wideevent.EmitterFunc(func(*wideevent.Event) {})})
	if err != nil {
		fmt.Println(err)
		return
	}
	engine := gin.New()
	engine.Use(wideEvents)
	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 records nothing.

func RedactQuery deprecated

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

RedactQuery does nothing.

Deprecated: the wide-event-logger v1 middleware (ginadapter.NewMiddleware) redacts request.query itself: every value becomes "redacted" unless its parameter is in Options.QueryAllowlist. Drop RedactQuery from your pre-enricher; it stays so enrichers that mount or call it keep compiling once they move to wide-event-logger v1.

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