Keycloak SSO
SES authenticates every user with OpenID Connect (OIDC, Authorization Code + PKCE). The platform ships with a Keycloak realm as the default and test identity provider — it is bundled with the deployment so you can start working immediately.
The bundled Keycloak is ideal for development, evaluation and small installations. For production you will usually point SES at your own OIDC provider instead — whether that's a Keycloak you operate, or an external provider such as Microsoft Entra ID (Azure AD), Google, Auth0 or SURFconext. SES speaks standard OIDC, so any conforming provider works.
You can also set up and manage your own identity providers per institute from the admin panel — see Identity providers.
Integrating other OIDC providers (identity providers)
External authentication sources are registered in SES as identity providers. You can have several per institute (for example one for students and one for staff). SES never changes identity policy — the provider is used as-is.
Registering an identity provider
- In the admin panel go to Administration → Organisation → Identity providers → Add.
- Select Institute and give the provider a Name (e.g.
Microsoft Entra ID). - Choose Provider type: OIDC and enable Active.
- Fill in the provider's OIDC endpoints:
| Endpoint | Value |
|---|---|
| Authorization URL | <provider>/authorize |
| Token URL | <provider>/token |
| Userinfo URL | <provider>/userinfo |
| JWKS URL (keys) | <provider>/jwks |
| End-session URL | <provider>/logout |
| Issuer | <provider> |
- Enter the Client ID and Client secret SES uses with that provider (secret is encrypted at rest).
- Map the claims SES needs:
| Field | Purpose | Typical source |
|---|---|---|
| Username claim | Used as the student number | sub |
| Role claim | Contains role information | roles (or https://ses/roles) |
| Teacher role value | Grants teacher access | ses-teacher |
| Admin role value | Grants admin/staff access | ses-admin |
| Faculty claim | Scopes a teacher to a faculty | faculty |
- Save.
Making roles work
SES reads the role claim and maps its values to platform roles
(ses-superuser, ses-admin, ses-teacher, ses-student). Your provider
must issue those role values (as realm/claim roles or a custom claim), or SES
cannot grant admin/teacher access. Configure this either in the provider
itself or via a claim mapper.
Making tenant access work
Tenant access is enforced by the institutes claim. Every identity
provider must ensure a user's ID token carries an institutes claim listing
the institutes the user may enter. Add an attribute/mapper on the provider
side; without it, the login is refused.
A provider that does not issue the SES role values and the institutes claim
will authenticate users but grant no admin access and no tenant
access. Configure both before enabling the provider.
One way to ease integration: point SES at the bundled Keycloak and use its
broker role mapper or a custom protocol mapper so your external IdP
sessions still produce the roles and institutes claims SES expects.
Realm structure
The ses realm contains roles, a client, and a dedicated claim scope.
Roles
| Role | Description |
|---|---|
ses-superuser | Full superuser (is_superuser=True) |
ses-admin | Staff access (is_staff=True) |
ses-teacher | Faculty-scoped exam management |
ses-student | Exam access only |
Client: ses-server
| Setting | Value |
|---|---|
| Client ID | ses-server |
| Flow | Authorization Code + PKCE |
| Scopes | openid profile email roles ses-claims |
Client scope: ses-claims
| Mapper | Claim | Source |
|---|---|---|
| realm_roles | roles | User's realm roles |
| faculty | faculty | User attribute |
| student_number | student_number | User attribute |
| employee_number | employee_number | User attribute |
Access claim: institutes
Tenant access is enforced through a signed institutes claim in the ID
token. If a user's token does not contain the target institute, SES refuses
the login — for every tenant.
This is a separate Keycloak setup, configured in the bundled ses realm:
| Piece | Where in Keycloak | What it does |
|---|---|---|
| Scope | Client scope ses-claims | Carries the claim into the ID token (the client includes this scope) |
| Mapper | institutes-mapper on ses-claims (type "List user attribute") | Reads the user's institutes attribute and emits it as the institutes claim |
| Per-user data | User attribute institutes | Which institutes the user may enter (multivalued, e.g. superuser/admin = [default-institute, test-institute], others = [default-institute]) |
Add the institute to the user's institutes attribute in Keycloak; the mapper
turns it into the signed claim SES checks at login.
A user cannot reach an institute's data unless the institutes claim
explicitly includes it — even if the user has a valid Keycloak account.
Accessing the admin console
- URL:
https://<keycloak-domain>/admin/ - Username:
admin - Password: value of
KEYCLOAK_ADMIN_PASSWORDin.env.secrets
OIDC endpoints
| Endpoint | URL |
|---|---|
| Authorization | https://<keycloak-domain>/realms/ses/protocol/openid-connect/auth |
| Token | http://keycloak:8080/realms/ses/protocol/openid-connect/token |
| JWKS | http://keycloak:8080/realms/ses/protocol/openid-connect/certs |
| Logout | https://<keycloak-domain>/realms/ses/protocol/openid-connect/logout |
Test users (seed data)
| Username | Roles | Identifier |
|---|---|---|
superuser | ses-superuser | employee_number=SES-SUP |
admin | ses-admin | employee_number=SES-ADM |
teacher1 | ses-teacher | faculty=CS |
teacher2 | ses-teacher | faculty=MATH |
student1 | ses-student | student_number=S12345678 |
student2 | ses-student | student_number=S87654321 |
Security features
- PKCE (S256) — proof key for code exchange
- State parameter — CSRF protection
- Nonce — replay-attack prevention
- JWKS signature verification — ID-token signature validation