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
- Variables
- type Config
- type Provider
- func (p *Provider) AuthorizeURL(state, redirectURI string) string
- func (p *Provider) AuthorizeURLWithPKCE(ctx context.Context, state, redirectURI string) (string, string, error)
- func (p *Provider) DisplayName() string
- func (p *Provider) ExchangeCode(ctx context.Context, code, redirectURI string) (*auth.OAuthUser, error)
- func (p *Provider) ExchangeCodeWithVerifier(ctx context.Context, code, redirectURI, codeVerifier string) (*auth.OAuthUser, error)
- func (p *Provider) Name() string
Constants ¶
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.
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 ¶
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 ¶
NewProvider builds a generic OIDC provider. It performs no network I/O: discovery happens on first use.
func (*Provider) AuthorizeURL ¶
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 ¶
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.