How to Set Up OIDC Authentication in Listmonk with External Identity Providers
Listmonk supports OpenID Connect (OIDC) authentication through its built-in auth package, enabling Single Sign-On (SSO) via standards-compliant identity providers like Keycloak, Authentik, or Google Workspace by configuring the OIDC struct in models/settings.go and exposing the /auth/oidc endpoints.
Listmonk provides native OIDC support that integrates external identity providers directly into the authentication flow. This implementation allows administrators to delegate user verification to corporate IdPs while automatically provisioning accounts with specific role assignments. Setting up Listmonk OIDC authentication requires configuring provider endpoints, credentials, and optional auto-user creation settings in the application's configuration layer.
OIDC Configuration Structure
The OIDC settings are defined in models/settings.go (lines 55-64) as part of the global Settings model. This structure stores all parameters required to negotiate with external identity providers.
The configuration includes the provider URL, client credentials, redirect URL, and flags for automatic user provisioning:
ProviderURL: The OIDC issuer URL (e.g.,https://keycloak.example.com/realms/<realm>)ClientIDandClientSecret: Credentials obtained from your IdPRedirectURL: The callback endpoint (typicallyhttps://<your-host>/auth/oidc)AutoCreateUsers: Boolean flag to provision new accounts automaticallyDefaultUserRoleIDandDefaultListRoleID: Role assignments for auto-created users
Initialization Flow
When Listmonk starts with OIDC enabled (cfg.OIDC.Enabled == true), the auth.New function calls initOIDC (internal/auth/auth.go lines 48-73). This initialization performs three critical operations:
- Creates an OpenID Connect provider using
oidc.NewProviderto connect to the discovery endpoint - Builds an OAuth2 configuration with scopes
openid,profile, andemail - Prepares an ID token verifier to validate incoming authentication tokens
This setup establishes the secure handshake between Listmonk and your external identity provider before any user attempts to log in.
Authentication Flow
The OIDC authentication process uses two HTTP endpoints registered in cmd/handlers.go (lines 254-256). These handlers orchestrate the redirect to the IdP and the subsequent callback processing.
Initiating Login
The /auth/oidc endpoint triggers the OIDCLogin handler (defined in cmd/auth.go). This handler generates a cryptographically secure state and nonce payload, stores it in a browser cookie for CSRF protection, and redirects the user to the provider's authorization URL via Auth.GetOIDCAuthURL.
func (a *App) OIDCLogin(c echo.Context) error {
nonce, _ := uuid.NewRandom()
state := OIDCState{
RedirectURL: c.QueryParam("redirect"),
Nonce: nonce.String(),
}
b, _ := json.Marshal(state)
// Store nonce in a cookie, then redirect:
return c.Redirect(http.StatusFound,
a.auth.GetOIDCAuthURL(base64.URLEncoding.EncodeToString(b), nonce.Value()))
}
The user authenticates with the external provider, which then redirects back to the callback URL with an authorization code.
Handling the Callback
The callback request hits OIDCFinish (also in cmd/auth.go), which invokes auth.ExchangeOIDCToken to exchange the authorization code for an access token. This function verifies the ID token against the configured provider and extracts user claims (email, name, sub).
func (a *App) OIDCFinish(c echo.Context) error {
// Retrieve and validate the stored state/nonce
oidcToken, claims, err := a.auth.ExchangeOIDCToken(c.QueryParam("code"), nonce.Value)
if err != nil {
return err
}
// Find or create the user
user, err := a.getOrCreateUser(claims)
// Save session for subsequent requests
return a.auth.SaveSession(user, oidcToken, c)
}
If the email from the claims matches an existing Listmonk account, the user is logged in immediately. If no account exists and AutoCreateUsers is enabled, createOIDCUser creates a new database user and assigns the configured default roles.
Session Persistence
After successful token exchange, auth.SaveSession persists the user ID and OIDC token in a server-side session cookie. This session is then validated by Auth.Middleware on subsequent requests, maintaining the authenticated state without repeated IdP redirects.
Configuration Examples
You can configure OIDC via the Listmonk UI at Settings → Security → OIDC or by editing the configuration file directly.
config.toml Setup
Add the following section to your config.toml file:
[security.oidc]
enabled = true
provider_url = "https://keycloak.example.com/realms/myrealm"
client_id = "listmonk"
client_secret = "YOUR_CLIENT_SECRET"
redirect_url = "https://listmonk.example.com/auth/oidc"
auto_create_users = true
default_user_role_id = 2 # e.g., "Editor" role ID
default_list_role_id = 1 # e.g., "Subscriber" role ID
Programmatic Configuration
If embedding Listmonk as a library, configure OIDC programmatically before initializing the auth provider:
cfg := auth.Config{
OIDC: auth.OIDCConfig{
Enabled: true,
ProviderURL: "https://keycloak.example.com/realms/myrealm",
RedirectURL: "https://listmonk.example.com/auth/oidc",
ClientID: "listmonk",
ClientSecret: "YOUR_CLIENT_SECRET",
AutoCreateUsers: true,
DefaultUserRoleID: 2,
DefaultListRoleID: 1,
},
}
a, err := auth.New(cfg, db, callbacks, logger)
Summary
- OIDC configuration resides in
models/settings.goand supports all standard OIDC parameters including provider URLs, credentials, and auto-provisioning flags. - Initialization occurs in
internal/auth/auth.goviainitOIDC, which sets up the provider connection and token verifier. - Login flow uses
/auth/oidcendpoints defined incmd/handlers.goand implemented incmd/auth.go, handling state management and CSRF protection via nonce cookies. - Token exchange happens through
ExchangeOIDCToken, which validates ID tokens and extracts user claims beforeSaveSessioncreates the persistent browser session. - User provisioning automatically creates Listmonk accounts for authenticated OIDC users when
AutoCreateUsersis enabled, applying the specified default roles.
Frequently Asked Questions
What identity providers work with Listmonk OIDC?
Any standards-compliant OpenID Connect provider works with Listmonk, including Keycloak, Authentik, Google Workspace, Azure AD, and Okta. The implementation follows the OIDC discovery protocol (/.well-known/openid-configuration) to automatically retrieve provider metadata, requiring only the base provider URL in the configuration.
How does Listmonk handle user account creation for OIDC logins?
When AutoCreateUsers is enabled in the OIDC configuration, Listmonk automatically creates a new user account if the email address from the OIDC claims does not match an existing account. The new user receives the roles specified in DefaultUserRoleID and DefaultListRoleID. If auto-creation is disabled, authentication fails for unknown users.
Where is the OIDC redirect URL configured in Listmonk?
The redirect URL is configured in the OIDC settings as RedirectURL (or redirect_url in TOML), which must match the callback URL registered with your identity provider. By default, Listmonk expects this endpoint at /auth/oidc on your host (e.g., https://listmonk.example.com/auth/oidc). This value is displayed in the UI at Settings → Security → OIDC for easy copying into IdP configurations.
What happens if OIDC token verification fails?
If ExchangeOIDCToken cannot verify the ID token (due to signature mismatch, expiration, or issuer mismatch), the authentication flow returns an error and the user is not logged in. The system logs the specific verification failure, and the user sees an authentication error page. The session cookie is only set after successful token validation and user retrieval or creation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →