oidc

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 26, 2026 License: MIT Imports: 13 Imported by: 0

README

gin-oidc

OpenID Connect (OIDC) middleware for the Gin web framework.

Installation

go get git.kronus.dev/gin/oidc

Usage

package main

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	"git.kronus.dev/gin/oidc"
)

func main() {
	r := gin.Default()

	store := cookie.NewStore([]byte("secret"))
	r.Use(sessions.Sessions("session", store))

	authGroup := r.Group("/oidc")
	oidc.Setup(authGroup)

	protected := r.Group("/protected")
	protected.Use(oidc.Auth())
	protected.GET("/", func(c *gin.Context) {
		c.String(200, "Protected content")
	})

	r.Run(":8080")
}

Environment Variables

Variable Description
GIN_OIDC_REALM_URL OIDC provider's well-known configuration URL
GIN_OIDC_CLIENT_ID OAuth2 client ID
GIN_OIDC_CLIENT_SECRET OAuth2 client secret
GIN_OIDC_SCOPE OAuth2 scopes (space-separated). Defaults to openid email. Validated against scopes_supported if provided by the OIDC configuration.

Routes

The middleware registers the following routes:

Route Description
GET /{basePath}/login Redirects to OIDC provider for authentication
GET /{basePath}/logout Clears session and redirects to home
GET /{basePath}/callback Handles OAuth2 callback from provider

Functions

Setup(r *gin.RouterGroup) error

Initializes the OIDC provider and registers authentication routes. Reads configuration from environment variables.

Auth() gin.HandlerFunc

Middleware that validates JWT tokens against the provider's JWKS. Redirects unauthenticated requests to the login route.

Implementing Whoami

A whoami function must be implemented by the client application to extract user information from the JWT token. Each client is responsible for:

  1. Choosing which JWT token parser to use (e.g., github.com/golang-jwt/jwt/v5)
  2. Optionally defining a custom Claims type to map custom fields from the token

Example with custom claims:

type CustomClaims struct {
    jwt.RegisteredClaims
    Email  string `json:"email"`
    Name   string `json:"name"`
    Roles  []string `json:"roles"`
}

func Whoami(c *gin.Context) {
    session := sessions.Default(c)
    tokenJSON := session.Get("token")
    
    var token oauth2.Token
    json.Unmarshal([]byte(tokenJSON.(string)), &token)
    
    claims := &CustomClaims{}
    jwt.ParseWithClaims(token.AccessToken, claims, func(t *jwt.Token) (interface{}, error) {
        return jwks.Keyfunc(t)
    })
    
    c.JSON(200, claims)
}

Provider Discovery

Supports OpenID Connect Discovery 1.0 specification. The provider configuration is fetched from the well-known endpoint and includes:

  • Required: issuer, authorization_endpoint, token_endpoint, jwks_uri
  • Recommended: userinfo_endpoint, scopes_supported, claims_supported
  • Optional: Various signing algorithms, encryption options, and authentication methods

Running Tests

go test ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Auth

func Auth() gin.HandlerFunc

Auth returns a Gin middleware that enforces authentication on protected routes. If no session token is present the request is aborted and the client is redirected to the login endpoint. If a token is present its access-token field is validated against the provider's JWKS; an invalid or expired token also results in a redirect to the login endpoint.

func Callback

func Callback(c *gin.Context)

Callback handles the authorization-code callback from the OIDC provider. If the session already contains a valid token the user is redirected to "/". If an expired token is present the user is redirected back to the login endpoint. Otherwise, the authorization code is exchanged for a token at the provider's token endpoint and the response is stored in the session before redirecting to "/".

func Login

func Login(c *gin.Context)

Login handles GET requests to the login endpoint. If the session already contains a valid OAuth2 token the user is redirected to "/". Otherwise, a new authorization state ID is generated, stored in the session, and the user is redirected to the provider's authorization endpoint with the configured client ID, scope, and callback URI.

func Logout

func Logout(c *gin.Context)

Logout clears the current session and redirects the user to "/".

func Setup

func Setup(r *gin.RouterGroup) error

Setup initializes the OIDC integration for the given Gin router group. It reads the following environment variables:

  • GIN_OIDC_REALM_URL (required) – base URL of the OIDC realm used to fetch provider metadata via InitProvider.
  • GIN_OIDC_CLIENT_ID (required) – OAuth2 client identifier.
  • GIN_OIDC_CLIENT_SECRET (required) – OAuth2 client secret.
  • GIN_OIDC_SCOPE (optional) – space-separated list of requested scopes. When the provider advertises supported scopes each requested scope is validated against that list. Defaults to "openid email".

On success the /login, /logout, and /callback routes are registered on r and nil is returned. An error is returned if any required variable is missing, the provider cannot be reached, or a requested scope is unsupported.

Types

type OIDC

type OIDC struct {
	Provider     *Provider
	BasePath     string
	ClientId     string
	ClientSecret string
	Scope        string
}

OIDC holds the configuration and state required to integrate a Gin router with an OpenID Connect provider. It is populated by Setup and used by the Login, Logout, Callback, and Auth handlers.

type Provider

type Provider struct {

	// Required fields
	Issuer                           string   `json:"issuer"`
	AuthorizationEndpoint            string   `json:"authorization_endpoint"`
	TokenEndpoint                    string   `json:"token_endpoint"`
	JwksUri                          string   `json:"jwks_uri"`
	ResponseTypesSupported           []string `json:"response_types_supported"`
	SubjectTypesSupported            []string `json:"subject_types_supported"`
	IdTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`

	// Recommended fields
	UserinfoEndpoint     string   `json:"userinfo_endpoint,omitempty"`
	RegistrationEndpoint string   `json:"registration_endpoint,omitempty"`
	ScopesSupported      []string `json:"scopes_supported,omitempty"`
	ClaimsSupported      []string `json:"claims_supported,omitempty"`

	// Optional fields
	ResponseModesSupported                     []string `json:"response_modes_supported,omitempty"`
	GrantTypesSupported                        []string `json:"grant_types_supported,omitempty"`
	ACRValuesSupported                         []string `json:"acr_values_supported,omitempty"`
	IdTokenEncryptionAlgValuesSupported        []string `json:"id_token_encryption_alg_values_supported,omitempty"`
	IdTokenEncryptionEncValuesSupported        []string `json:"id_token_encryption_enc_values_supported,omitempty"`
	UserinfoSigningAlgValuesSupported          []string `json:"userinfo_signing_alg_values_supported,omitempty"`
	UserinfoEncryptionAlgValuesSupported       []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
	UserinfoEncryptionEncValuesSupported       []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
	RequestObjectSigningAlgValuesSupported     []string `json:"request_object_signing_alg_values_supported,omitempty"`
	RequestObjectEncryptionAlgValuesSupported  []string `json:"request_object_encryption_alg_values_supported,omitempty"`
	RequestObjectEncryptionEncValuesSupported  []string `json:"request_object_encryption_enc_values_supported,omitempty"`
	TokenEndpointAuthMethodsSupported          []string `json:"token_endpoint_auth_methods_supported,omitempty"`
	TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
	DisplayValuesSupported                     []string `json:"display_values_supported,omitempty"`
	ClaimTypesSupported                        []string `json:"claim_types_supported,omitempty"`
	ServiceDocumentation                       string   `json:"service_documentation,omitempty"`
	ClaimsLocalesSupported                     []string `json:"claims_locales_supported,omitempty"`
	UiLocalesSupported                         []string `json:"ui_locales_supported,omitempty"`
	ClaimsParameterSupported                   bool     `json:"claims_parameter_supported,omitempty"`
	RequestParameterSupported                  bool     `json:"request_parameter_supported,omitempty"`
	RequestUriParameterSupported               bool     `json:"request_uri_parameter_supported,omitempty"`
	RequireRequestUriRegistration              bool     `json:"require_request_uri_registration,omitempty"`
	OpPolicyUri                                string   `json:"op_policy_uri,omitempty"`
	OpTosUri                                   string   `json:"op_tos_uri,omitempty"`
}

Provider represents the OpenID Connect provider metadata retrieved from the discovery document as defined by the OpenID Connect Discovery 1.0 specification (https://openid.net/specs/openid-connect-discovery-1_0.html). Required, recommended, and optional fields are mapped directly from the JSON discovery document.

func InitProvider

func InitProvider(realmUri string) (*Provider, error)

InitProvider fetches and decodes the OpenID Connect discovery document from realmUri. It returns a populated Provider on success, or an error if the HTTP request fails, the server returns a non-200 status, the Content-Type is not "application/json" (with or without a charset parameter), or the response body cannot be decoded as JSON.

Source Files

  • oidc.go
  • provider.go

Jump to

Keyboard shortcuts

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