oidc

package
v0.25.1 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Overview

Package oidc implements a generic, configurable-issuer OpenID Connect login provider — the one that lets an organization sign in to dbbat with Google Workspace, Okta, Microsoft Entra, Keycloak, Authentik or anything else that speaks OIDC discovery.

It differs from the Slack provider in one security-relevant way: Slack is trusted to answer its own userInfo endpoint, whereas a generic issuer is only trusted through a **verified ID token**. Every identity this package returns comes from a JWT whose signature was checked against the issuer's JWKS, and whose `iss`, `aud` and `exp` were checked against the configured issuer and client id.

Index

Constants

View Source
const DefaultGroupsClaim = "groups"

DefaultGroupsClaim is the ID-token claim read for directory group membership when the operator does not name another one. Okta, Keycloak and Entra all default to it.

View Source
const ProviderName = "oidc"

ProviderName is the key this provider is registered under, and the value stored in the `provider` column of user identities and OAuth states.

Variables

View Source
var (
	// ErrNoIDToken is returned when the token endpoint answered without an
	// id_token — the response of an OAuth2 server that is not an OIDC one.
	ErrNoIDToken = errors.New("token response carries no id_token")
	// ErrEmailNotVerified is returned when the issuer explicitly reports the
	// email claim as unverified.
	ErrEmailNotVerified = errors.New("email is not verified by the identity provider")
	// ErrEmailDomainNotAllowed is returned when the verified email's domain
	// is outside the configured allowlist.
	ErrEmailDomainNotAllowed = errors.New("email domain is not allowed")
	// ErrEmailRequired is returned when a domain allowlist is configured but
	// the ID token carries no email claim to check it against.
	ErrEmailRequired = errors.New("identity provider returned no email claim")
	// ErrIssuerRequired is returned by NewProvider when no issuer is set.
	ErrIssuerRequired = errors.New("oidc issuer is required")
)

Functions

This section is empty.

Types

type Config

type Config struct {
	// Issuer is the OIDC issuer URL, e.g. "https://accounts.google.com".
	// Discovery is done against <issuer>/.well-known/openid-configuration.
	Issuer string
	// ClientID and ClientSecret identify this dbbat instance to the issuer.
	ClientID     string
	ClientSecret string
	// Scopes requested at authorization time. "openid" is always included.
	Scopes []string
	// Label is the login-button text, e.g. "Acme SSO".
	Label string
	// EmailDomains, when non-empty, is the allowlist the *verified* email
	// claim's domain must belong to. It is the generic equivalent of the
	// Slack provider's workspace gating.
	EmailDomains []string
	// GroupsClaim names the ID-token claim carrying directory group
	// membership. Empty defaults to "groups". The values are read verbatim:
	// Entra sends group **object ids**, Okta and Keycloak send names, and
	// this package does not try to tell them apart.
	GroupsClaim string
}

Config is the operator-supplied configuration of the generic provider.

type Provider

type Provider struct {

	// HTTPClient, when set, is used for discovery, JWKS fetches and token
	// exchange. Tests point it at an httptest issuer.
	HTTPClient *http.Client
	// contains filtered or unexported fields
}

Provider implements auth.OAuthProvider, auth.PKCEProvider and auth.DisplayNamer against any OIDC-compliant issuer.

func NewProvider

func NewProvider(cfg Config) (*Provider, error)

NewProvider builds a generic OIDC provider. It performs no network I/O: discovery happens on first use.

func (*Provider) AuthorizeURL

func (p *Provider) AuthorizeURL(state, redirectURI string) string

AuthorizeURL satisfies auth.OAuthProvider. The API drives this provider through AuthorizeURLWithPKCE instead (it implements auth.PKCEProvider), so this is the degraded path: same URL, no code challenge. It returns "" when discovery fails, which the caller surfaces as a failed login rather than a redirect to nowhere.

func (*Provider) AuthorizeURLWithPKCE

func (p *Provider) AuthorizeURLWithPKCE(
	ctx context.Context,
	state, redirectURI string,
) (string, string, error)

AuthorizeURLWithPKCE builds the authorization URL carrying an S256 code challenge, and returns the verifier the caller must persist alongside the OAuth state row. Some IdPs (and every sane deployment) require PKCE.

func (*Provider) DisplayName

func (p *Provider) DisplayName() string

DisplayName returns the operator-configured login-button label.

func (*Provider) ExchangeCode

func (p *Provider) ExchangeCode(ctx context.Context, code, redirectURI string) (*auth.OAuthUser, error)

ExchangeCode exchanges an authorization code without PKCE.

func (*Provider) ExchangeCodeWithVerifier

func (p *Provider) ExchangeCodeWithVerifier(
	ctx context.Context,
	code, redirectURI, codeVerifier string,
) (*auth.OAuthUser, error)

ExchangeCodeWithVerifier completes the OIDC code flow: it exchanges the authorization code, **verifies the ID token's signature, issuer, audience and expiry against the issuer's JWKS**, then applies the email-verification and domain-allowlist policy before returning a normalized user.

Neither the client secret nor any token ever reaches an error string or a log line: failures are described, not quoted.

func (*Provider) Name

func (p *Provider) Name() string

Name returns "oidc".

Jump to

Keyboard shortcuts

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