How It Works
Architecture overview
┌─────────────────────────┐
│ SP Portal │
│ portal.clickid.eu │
│ (Nuxt 3) │
└────────────┬─────────────┘
│ Admin API
┌──────────────────▼──────────────────────┐
│ Keycloak 24 │
│ auth.clickid.eu │
[Service Provider] │ │ [PostgreSQL]
──── SAML 2.0 ───► │ ┌──────────────────────────────────┐ │ ◄──────────
│ │ Sector-ID Mapper SPI (Java) │ │
│ │ HMAC-SHA256 pseudonym generator │ │
│ └──────────────────────────────────┘ │
[User Browser] │ │
── Login Form ───► │ ┌──────────────────────────────────┐ │
│ │ EU Theme (FTL templates) │ │
│ │ #003DA6, WCAG 2.1 accessible │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘
Realms: clickid (live) | clickid-sandbox (testing)
Components
Keycloak 24
Keycloak is the IdP core. It handles:
- SAML 2.0 protocol — AuthnRequest parsing, Response generation, signing
- User management — registration, credential storage, account management
- MFA — TOTP (Google Authenticator, Authy) and passkey (WebAuthn) support
- Session management — SSO sessions, logout (SLO)
- Realm isolation — live and sandbox realms share the same Keycloak instance but have entirely separate user databases, SP registrations, and signing keys
Keycloak is configured entirely via realm import — the clickid and clickid-sandbox realms are imported from JSON at startup, so no manual Keycloak admin UI configuration is required.
Sector-ID Mapper SPI
A custom Java SPI extension that replaces Keycloak's default NameID generation. Instead of exposing the internal user ID or email address, it computes a pseudonymous, per-SP identifier:
sectorId = BASE64URL(HMAC-SHA256(userId + "|" + spEntityId, pepper))[:24]
This gives every SP a stable, unique identifier for each user — but SPs cannot correlate users across services. See Sector-ID concept for full details.
EU Theme
A custom Keycloak FreeMarker (FTL) theme providing:
- Brand colors:
#003DA6blue (EU institutional blue),#FFCC00yellow accents - WCAG 2.1 Level AA accessibility compliance
- Responsive layout suitable for both desktop and mobile
- Dutch (
nl) and English (en) localisation - Clear login, registration, TOTP setup, and error pages
SP Portal
A Nuxt 3 web application at portal.clickid.eu that gives SP developers a self-service interface to:
- Register new service providers (paste SAML metadata XML or provide metadata URL)
- Manage sandbox and live SP registrations
- View their sector-ID configuration
- Promote a sandbox SP to live
The portal authenticates portal users via Keycloak OIDC (separate from the SAML SPs it manages) and calls the Keycloak Admin REST API to create and configure SP clients.
Two realms
| Realm | Endpoint base | Purpose |
|---|---|---|
clickid | https://auth.clickid.eu/realms/clickid | Live production |
clickid-sandbox | https://auth.clickid.eu/realms/clickid-sandbox | Testing and development |
The sandbox realm uses relaxed authentication policies: no TOTP required, short passwords accepted, no email verification. It is designed for SP integration testing, not for real users.
Because each realm has its own pepper, a user's sector-ID in the sandbox realm will not match their sector-ID in the live realm. This is by design — do not attempt to map sandbox IDs to live IDs.
Authentication flow
The standard SAML 2.0 SP-initiated SSO flow:
- User visits SP — the service provider determines the user is not authenticated.
- SP generates AuthnRequest — the SP constructs a SAML
AuthnRequestand redirects the user's browser to the ClickID IdP via HTTP-Redirect binding. - IdP receives request — Keycloak parses the
AuthnRequest, validates the SP's entity ID against registered clients, and checks the request signature (if the SP signs requests). - User authenticates — the user is presented with the EU Theme login page. They enter their email and password. If MFA is enrolled, they are prompted for their TOTP code or passkey.
- Session check — if an existing Keycloak SSO session is valid for this browser, steps 4 is skipped (transparent SSO).
- Sector-ID computed — the Sector-ID Mapper SPI computes the pseudonymous identifier for this
(userId, spEntityId)pair. - SAML Response generated — Keycloak builds a signed SAML Response containing the
NameID(the sector-ID) and any configured attribute statements (e.g. assurance level). The Response is signed with RSA-SHA256. - Response POSTed to SP — the browser submits the Response to the SP's Assertion Consumer Service (ACS) URL via HTTP-POST binding. The SP validates the signature, extracts the NameID, and establishes a session.
User registration flow
ClickID supports self-sovereign registration — users create their own accounts without any pre-provisioning by an administrator.
- User visits SP → SP initiates SSO → ClickID login page shown
- User clicks "Register" on the login page
- Email and password — user enters their email address and a password (minimum length enforced)
- Email verification — a verification link is sent to the provided address. The user must click the link to proceed. (Skipped in sandbox realm.)
- MFA setup — user is prompted to configure TOTP using an authenticator app, or register a passkey. This step is required before first login completes in the live realm.
- Account active — user is redirected back to the SP with a valid SAML assertion.
On subsequent visits, returning users go directly to the login form (email + password + TOTP/passkey).
Users can manage their credentials — change password, add/remove TOTP devices, manage passkeys — at https://auth.clickid.eu/realms/clickid/account.