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

keycloak

package
v1.3.0 Latest Latest
Warning

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

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

Documentation

Overview

Package keycloak enriches OIDC identities from the Keycloak Admin API: composite realm roles, client roles of one client, group paths and user attributes, and refuses users without the required roles or groups. Client.Enrich has the auth.Hook shape, so it plugs into oidc.Options.OnLogin.

The client authenticates with the client credentials grant of a service account by default (the password grant breaks as soon as the admin user gets an OTP credential). It never logs and starts no goroutine.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client reads users' authorization from the Keycloak Admin API. It caches its access token until 30 s before expiry, or until the Admin API answers 401 to it (then the next call requests a new one), and the client UUID of ClientRolesClientID after the first successful lookup. It is safe for concurrent use.

func New

func New(options *Options) (*Client, error)

New validates options and returns a Client; it does no I/O. It does not modify options, and changing them afterwards has no effect.

func (*Client) Enrich

func (c *Client) Enrich(ctx context.Context, identity *auth.Identity) (*auth.Identity, error)

Enrich has the auth.Hook shape; identity.Subject is the Keycloak user ID. It returns a Clone with OIDCRoles (composite realm roles), OIDCClientRoles (composite roles of ClientRolesClientID, else none), Groups (paths) and Attributes replaced by the Admin API's answer. A missing required role or group is an *auth.Error{Kind: auth.ErrForbidden} whose Reason names it (never sent to the client); an API failure is a plain error.

Example
package main

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

	"github.com/govengers/auth"
	"github.com/govengers/auth/internal/fakeprovider"
	"github.com/govengers/auth/oidc/keycloak"
)

// startExampleKeycloak serves the test fake in place of Keycloak: realm "staff" with one user and a
// service account client "app-admin".
func startExampleKeycloak() (*httptest.Server, error) {
	server := httptest.NewUnstartedServer(nil)
	base := "http://" + server.Listener.Addr().String()
	handler, err := fakeprovider.NewOIDCHandler(&fakeprovider.OIDCOptions{
		IssuerURL: base + "/realms/staff", ClientID: "app", ClientSecret: "app-secret",
		KeycloakRealm: "staff", KeycloakClientID: "app-admin", KeycloakClientSecret: "service-secret",
		User: fakeprovider.OIDCUser{Subject: "user-1", RealmRoles: []string{"admin"}, Groups: []string{"/staff/scoring"}},
	})
	if err != nil {
		server.Close()
		return nil, err
	}
	server.Config.Handler = handler
	server.Start()
	return server, nil
}

func main() {
	server, err := startExampleKeycloak()
	if err != nil {
		fmt.Println(err)
		return
	}
	defer server.Close()
	client, err := keycloak.New(&keycloak.Options{
		URL:                server.URL, // e.g. https://sso.example.com
		Realm:              "staff",
		ClientID:           "app-admin", // service account with the realm-management roles view-users, query-users and query-groups (docs/wiki/OIDC.md)
		ClientSecret:       "service-secret",
		RequiredRealmRoles: []string{"admin"},
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	// Usually wired as oidc.Options{OnLogin: client.Enrich}; the oidc provider calls it after the callback.
	enriched, err := client.Enrich(context.Background(), &auth.Identity{Provider: "keycloak", Subject: "user-1", Active: true})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(enriched.OIDCRoles, enriched.Groups)
}
Output:
[admin] [/staff/scoring]

type GrantType

type GrantType string

GrantType is how the client obtains its Admin API token.

const (
	GrantTypeClientCredentials GrantType = "client_credentials" // default: the client's service account
	GrantTypePassword          GrantType = "password"           // admin-cli password grant; breaks when the user gets an OTP credential
)

The supported grants.

type Options

type Options struct {
	URL                 string    // required: Keycloak base URL; https, or http on a loopback host
	Realm               string    // required: realm of the users
	AuthenticationRealm string    // realm the service account logs into; default Realm (e.g. "master" for a master admin)
	GrantType           GrantType // default GrantTypeClientCredentials
	ClientID            string    // required for client credentials; password grant default "admin-cli"
	ClientSecret        string    // required for client credentials; optional for the password grant
	Username, Password  string    // required for the password grant
	ClientRolesClientID string    // optional: clientId whose client roles become OIDCClientRoles
	RequiredRealmRoles  []string
	RequiredClientRoles []string     // needs ClientRolesClientID
	RequiredGroups      []string     // group paths ("/parent/child")
	HTTPClient          *http.Client // default 10 s timeout; a redirect fails the call
}

Options configure a Client.

Jump to

Keyboard shortcuts

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