Enterprise

SSO for your wiki: SAML, OIDC & Google

Wikantik delegates authentication to your identity provider — SAML 2.0, OpenID Connect, or Google — via the pac4j library. Every SSO login rotates the HTTP session, fails closed on account-name collisions, and coexists seamlessly with local password auth.

SSO that fits your IdP

Most enterprise wikis treat SSO as an afterthought — a plugin that breaks on every upgrade. Wikantik builds it into the authentication stack from the start. The SSO implementation uses pac4j, a mature Java security library, so it speaks whatever your IdP speaks: SAML 2.0 metadata XML, OIDC discovery documents, or the Google-specific quirks that trip up most implementations (Google omits preferred_username, so Wikantik maps the login name from email instead).

SSO is purely additive. When enabled, the login page shows a provider button alongside the local form. Your local admin account keeps working during the rollout, and you can run SAML and OIDC simultaneously with wikantik.sso.type = both.

SAML 2.0 and OIDC — how they're configured

Both protocols are configured in wikantik-custom.properties (or injected as environment variables in Docker via WIKANTIK_SSO_* — secrets never land in git).

OIDC quick start (Google)

Point Wikantik at the provider's discovery URI, supply the client credentials, and register the redirect URI:

wikantik.sso.enabled = true
wikantik.sso.type = oidc
wikantik.sso.oidc.discoveryUri = https://accounts.google.com/.well-known/openid-configuration
wikantik.sso.oidc.clientId = <client-id>.apps.googleusercontent.com
wikantik.sso.oidc.clientSecret = <client-secret>
wikantik.sso.claimMapping.loginName = email

The redirect URI is wikantik.baseURL + /sso/callback. Google enforces an exact match — Wikantik deliberately uses a clean, parameter-free callback URL so strict IdPs don't reject it.

SAML 2.0

Provide the IdP metadata XML path and your SP entity ID. Wikantik only supports HTTP-Redirect binding for the authentication request (not HTTP-POST), so set the binding accordingly in your IdP. The Assertion Consumer Service URL is the same /sso/callback path.

Google OIDC is live in production at wiki.wikantik.com using this exact configuration. It works cleanly behind Cloudflare Tunnel with no extra header gymnastics.

Identity binding and the claim config

The trickiest part of any SSO integration is deciding which IdP claim to use as the account-link key. Wikantik makes this explicit with wikantik.sso.identityClaim:

  • Default: sub — the IdP's immutable subject identifier. Safe even if the user changes their email or username.
  • preferred_username — use this if you deliberately want to trust a mutable claim (e.g. to let a renamed user pick up their existing local account). The risk is that a claim change breaks the link.

Claim values are sanitised before use: multi-valued claims are normalised to their first scalar element, and blank or control-character login names are rejected outright. The configured claimMapping.* properties are automatically bridged into the JAAS LoginModule — you set them once under wikantik.sso.* and they take effect.

Security: session rotation, fail-closed binding, CSRF

These three properties are non-negotiable for a production SSO deployment, so Wikantik handles them without configuration:

Session fixation defense

A successful SSO login always rotates the HTTP session. The old session ID is invalidated and a fresh one is issued before any privileged state is written. This closes the classic fixation attack where an attacker pre-seeds a session token.

Fail-closed account binding

Auto-provisioned SSO profiles carry an sso.subject marker attribute. When an SSO login arrives for a name that already exists locally, Wikantik checks for that marker. If it's absent — meaning the account was created by a human admin, not SSO auto-provisioning — the login is refused. The attacker cannot claim the admin account by registering a matching Google identity. The user and admin are notified with a clear error code at /login?error=.

CSRF handling for SAML

The SAML HTTP-POST callback at /sso/callback is exempt from Wikantik's synchronizer-token CSRF filter. This is correct: the IdP-signed assertion is its own CSRF defense — the signature over the assertion timestamp and audience makes replaying the POST useless. OIDC uses the standard authorization-code flow, which is protected by the state parameter.

How SSO pairs with SCIM provisioning

SSO handles the login flow and auto-provisions local profiles on first successful login. If your IdP also manages group membership or needs to create and deactivate accounts out-of-band, SCIM provisioning is the complementary path: SCIM-created accounts authenticate via SSO by default (a random password is generated at creation and never revealed).

Frequently asked questions

Which identity providers are supported for SSO?

Any SAML 2.0 IdP and any OIDC-compliant provider via pac4j. Google OIDC is used in production. LDAP and local database authentication run alongside SSO — all authentication methods are additive. You can run SAML and OIDC simultaneously with wikantik.sso.type = both.

Can I trust preferred_username instead of sub as the identity claim?

Yes, by setting wikantik.sso.identityClaim = preferred_username. Be aware that preferred_username is a mutable claim — if the IdP changes it, the account link breaks. The default sub is the immutable IdP subject and is the safer choice for most deployments.

What stops an attacker from taking over an existing account via SSO name collision?

SSO never adopts a pre-existing non-SSO-linked local account of the same name. Auto-provisioned profiles carry an sso.subject marker; a name collision without a matching marker fails closed — login is refused rather than silently granting access to the pre-existing account.