Overview
The validated baseline is the openSUSE-based grommunio appliance 2026.06.1. The examples consistently use the neutral appliance domain https://mail.example.test; paths such as /web/, /admin/, /auth/, /chat/, /meet/ and /files/ live on the same appliance.This article shows how to install grommunio-auth on an existing grommunio appliance and operate the grommunio realm in Keycloak cleanly.
Meet-specific adapter steps do not belong here. This guide focuses on grommunio-auth, grommunio Web, Keycloak, federation, MFA, discovery and login flow.
Tested environment
grommunio 2026 on the openSUSE-based grommunio appliance.
All appliance commands are run directly on the grommunio appliance.
Public examples consistently use the neutral appliance domain https://mail.example.test.
1. Starting point & requirements
The starting point is an installed grommunio appliance reachable via HTTPS at https://mail.example.test. This guide intentionally builds on the installation series: groupware base first, then antispam, then central authentication and MFA.
For a production project, prepare a fixed FQDN, working DNS, TLS, NTP, tested admin access, current packages, and a rollback path. SSO changes the login path, so validate the base services and document the current state first.
# Run on the grommunio appliancehostname -fcat /etc/os-releaserpm -q grommunio-auth grommunio-keycloak grommunio-web gromox grommunio-admin-apisystemctl is-active nginx php-fpm mariadb grommunio-keycloak gromox-http gromox-zcorecurl -k -I https://mail.example.test/web/
Expected result: the host reports mail.example.test, the services are active, and grommunio Web returns an HTTP header. If nginx or grommunio-keycloak is not active, fix the service state before you continue with Keycloak clients or MFA.
2. Step-by-step guide
2.1 Install packages and check services
Install grommunio-auth and grommunio-keycloak from the configured grommunio repositories. Then check that Keycloak listens locally on port 9080 and nginx publishes the public /auth paths.
# Run on the grommunio appliancezypper refreshzypper install grommunio-auth grommunio-keycloaksystemctl enable --now grommunio-keycloak nginx php-fpm mariadbsystemctl status grommunio-keycloak --no-pagerss -ltnp | grep ':9080'
If port 9080 is not listening, start with journalctl -u grommunio-keycloak. Common causes are database access, hostname values, or a missing Keycloak build after package installation.
2.2 Start the grommunio-auth setup
The setup connects the grommunio database, Keycloak, and the web components. Run it interactively on the appliance and work through the fields one by one.
# Run on the grommunio appliance/usr/share/grommunio-auth/setup-grommunio-auth.sh
Enter the FQDN users will really use later. In the validated environment this is https://mail.example.test. Do not use a random URL or a local port when users will access the system through the real hostname.
Select the Keycloak integration and let the setup prepare the local grommunio Keycloak connection. Afterwards, validate the generated files and restart the relevant services.
2.3 Open the grommunio realm and do not work in master
Log in to the Keycloak Admin Console and switch to the grommunio realm. The master realm is for Keycloak administration only. The grommunio application, user federation, MFA policy, and broker setup belong to the grommunio realm.
Check that the realm is enabled and Require SSL is set to External requests. If you work in master by mistake, clients and identity providers end up in the wrong place and grommunio Web will not find the expected OIDC configuration.
2.4 Validate the grommunio client
Open Clients in the grommunio realm. The grommunio client must exist. This is the OIDC application that redirects users from grommunio Web to Keycloak and later validates tokens.
Open the grommunio client. In the tested environment, Root URL and Home URL are set to https://mail.example.test:443/ and the redirect URI allows https://mail.example.test/*. In a real environment, set the actual public URL of your grommunio installation here.
The client is confidential and uses client ID plus secret. The secret is not published. Copy it from Keycloak and place it in /etc/gromox/keycloak.json.
Also check the client scopes. Standard scopes such as profile and email must be available because grommunio needs name and email claims. The grommunio-audience mapper ensures tokens contain the expected audience for the grommunio client.
# Run on the grommunio appliance/usr/share/grommunio-keycloak/bin/kcadm.sh get clients \-r grommunio \-q clientId=grommunio \--fields id,clientId,enabled,redirectUris,webOrigins,standardFlowEnabled,directAccessGrantsEnabled,serviceAccountsEnabled/usr/share/grommunio-keycloak/bin/kcadm.sh get clients/<CLIENT_UUID>/protocol-mappers/models \-r grommunio \--fields name,protocolMapper,config
Expected result: an enabled OIDC client named grommunio with Standard Flow, matching redirect URI, and an oidc-audience-mapper. If the mapper is missing, applications may receive a token but fail audience validation.
2.5 Validate user federation from grommunio
Users come from the grommunio environment in this installation. Open User federation in the grommunio realm and check that the grommunio provider is enabled.
The provider detail page must be enabled. Keycloak can then expose grommunio users without duplicating them as local Keycloak accounts.
Search for * under Users. In the validated environment, synthetic users such as alex@example.test, alice@example.test, bob@example.test, and meet@example.test are visible. In production, this is where your real grommunio users appear.
2.6 Enable MFA in the grommunio realm and test login
MFA belongs in the grommunio realm, not in master. Open Authentication and work with the Browser flow or a copy of it. For production, create your own flow copy so built-in flows remain untouched.
For a controlled rollout, enable MFA per user first. In the grommunio realm, open Users, search for the target user, open the user, and add Configure OTP under Required user actions. Save the user afterwards.
Set the current realm in the upper left corner to grommunio.
Open Users and search for the user, for example alex@example.test.
Open the user and add Configure OTP under Details or Required user actions.
Save the user and make sure the user fully logs out once.
Open https://mail.example.test/web/ and run the login again.
Keycloak displays TOTP enrollment with a QR code during the next login. The user scans the code with an authenticator app and confirms the first one-time code.
If MFA should be mandatory for all users, copy the Browser flow in the grommunio realm, add or enable the OTP step as required, and bind this copied flow under Bindings as the Browser flow. Do this only after you have tested a break-glass admin account and documented the rollback path.
Then open grommunio Web. The user is authenticated by Keycloak and returns to grommunio Web after a successful login.
2.7 Broker an existing Keycloak or identity provider
If you already run a central Keycloak or another OIDC provider, add it as an Identity Provider in the grommunio realm. In the lab, a second Keycloak context on the same isolated VM was used as the upstream simulation; in production, use the real central IdP and its real FQDN.
The alias in this example is forgeone-keycloak. The critical values are the Redirect URI shown in the grommunio realm and the upstream OIDC endpoints: Authorization URL, Token URL, Logout URL, and User Info URL.
Create a confidential client on the upstream Keycloak for this broker. Use the redirect URI shown by the grommunio realm identity provider. Then enter client ID and secret in the broker configuration. The secret is not published.
For logout round-trips, grommunio needs an nginx redirect in this validated environment. It belongs to the nginx server context of the grommunio web instance: the same vhost that publishes /auth for mail.example.test. The appliance includes the Keycloak proxy locations from /usr/share/grommunio-common/nginx/locations.d/grommunio-auth.conf; the local override belongs in the nginx site configuration, not in keycloak.conf.
# /etc/nginx/conf.d/grommunio.conflocation ~ ^/auth/realms/grommunio/broker/[^/]+/endpoint/logout_response$ {return 302 $scheme://$host/web/;}
# Run on the grommunio appliancenginx -tsystemctl reload nginxcurl -k -I https://mail.example.test/auth/realms/grommunio/broker/forgeone-keycloak/endpoint/logout_response
Expected result after reload: HTTP 302 back to /web/. If a Keycloak error page appears instead, the nginx location block is not in the correct server context or is overridden by a more specific location.
2.8 Check the relevant configuration files
After setup, the files must match each other. The public browser URL is https://mail.example.test/auth/. The internal Keycloak process listens on http://localhost:9080/auth and is published through nginx.
# /etc/grommunio-keycloak/keycloak.confdb=mariadbproxy=edgehttp-port=9080http-relative-path=/authhttp-host=localhosthttp-enabled=truedb-username=grommunio_keycloakdb-password=<REDACTED>db-url-database=grommunio_keycloakdb-url-host=localhosthostname=mail.example.testhostname-strict=falsehostname-strict-https=falseproxy-headers=xforwarded
# /etc/grommunio-keycloak/grommunio.propertiesgrommunio.db-kind=org.mariadb.jdbc.Drivergrommunio.jdbc-url=jdbc:mariadb://localhost:3306/grommuniogrommunio.username=groauthgrommunio.password=<REDACTED>
{"realm": "grommunio","auth-server-url": "https://mail.example.test/auth/","ssl-required": "external","resource": "grommunio","verify-token-audience": true,"credentials": {"secret": "<CLIENT_SECRET>"},"confidential-port": 0,"policy-enforcer": {"credentials": {}}}
# /etc/grommunio-common/nginx/auth_allow.confallow 10.0.2.0/24;allow 127.0.0.1;
/etc/gromox/keycloak.json must be readable for grommunio Web, but not world-readable. In the validated environment, it is root:groweb and 0640. If ownership or permissions are wrong, login can fail even when the Keycloak client is correct.
# Run on the grommunio appliancestat -c '%U:%G %a %n' /etc/gromox/keycloak.json /etc/grommunio-keycloak/keycloak.conf /etc/grommunio-keycloak/grommunio.propertiessystemctl restart grommunio-keycloak nginx php-fpm gromox-http gromox-zcoresystemctl is-active grommunio-keycloak nginx php-fpm gromox-http gromox-zcore
2.9 Validate token, discovery, and introspection
Before sign-off, validate discovery, token issuance, and introspection. This confirms not only the UI path but also the OIDC foundation used by grommunio Web.
# Run on the grommunio appliancecurl -k https://mail.example.test/auth/realms/grommunio/.well-known/openid-configuration | jq '.issuer,.authorization_endpoint,.token_endpoint,.introspection_endpoint'TOKEN_RESPONSE=$(curl -ks \-d grant_type=password \-d client_id=grommunio \-d client_secret='<CLIENT_SECRET>' \-d username='alex@example.test' \-d password='<USER_PASSWORD>' \-d scope='openid profile email' \https://mail.example.test/auth/realms/grommunio/protocol/openid-connect/token)echo "$TOKEN_RESPONSE" | jq -r '.token_type,.expires_in'
Expected result: valid OIDC endpoints, a bearer token, and an expiry time. If you see invalid_client, check client ID and secret. If you see invalid_grant, check user password, MFA status, and required actions.
2.10 Add the audience mapper for token introspection
When grommunio Web introspects an access token against Keycloak, azp=grommunio is not enough on its own. The token also needs the grommunio client as an audience. If that audience is missing, Keycloak can log INTROSPECT_TOKEN_ERROR with invalid_token even though the browser login flow initially looks correct.
In the grommunio realm, open Clients -> grommunio -> Client scopes -> grommunio-dedicated -> Mappers -> Add mapper -> By configuration -> Audience. Create a mapper that writes the grommunio client audience into the access token and token introspection. ID token and lightweight access token stay disabled for this use case.
Mapper type: AudienceName: grommunio-self-audienceInclude Client Audience: grommunioAdd to ID token: OffAdd to access token: OnAdd to lightweight access token: OffAdd to token introspection: On
Request a fresh token afterwards. Existing tokens are not changed retroactively. Before the fix, the token payload usually contains azp=grommunio but no suitable aud entry for grommunio. After the fix, aud must contain grommunio.
# Run on the grommunio appliance, placeholders intentionally redactedACCESS_TOKEN='<ACCESS_TOKEN>'printf '%s' "$ACCESS_TOKEN" | awk -F. '{print $2}' | base64 -d -i 2>/dev/null | jq '{azp,aud,scope}'curl -k -sS -X POST \'https://mail.example.test/auth/realms/grommunio/protocol/openid-connect/token/introspect' \-u 'grommunio:<CLIENT_SECRET>' \-d "token=$ACCESS_TOKEN" | jq '{active,client_id,username,aud,azp,iss}'
The check is only complete when introspection returns active=true and aud=grommunio is visible. If introspection still reports invalid_token, verify that the mapper is really attached to the grommunio-dedicated scope of the grommunio client and that you are testing with a newly issued access token.
2.11 Check localhost:5000, gromox-http and IPv6 loopback
A common trap is not Keycloak itself but the local grommunio communication path. In the validated appliance, localhost resolves to ::1 first and gromox-http listens on [::1]:5000. If the local IPv6 loopback is disabled or broken, internal components can fail against localhost:5000. This does not mean that external IPv6 must be exposed; it concerns the local loopback path on the appliance.
# Run on the grommunio appliancegetent hosts localhostgetent ahosts localhostsysctl net.ipv6.conf.all.disable_ipv6 net.ipv6.conf.default.disable_ipv6 net.ipv6.conf.lo.disable_ipv6ip addr show loss -tlnp | grep ':5000'journalctl -u gromox-http -u gromox-zcore --since '30 minutes ago' --no-pager
The expected state is that lo has ::1/128 and gromox-http listens on [::1]:5000. Also check that /etc/gromox/gromox.cfg, or the still evaluated http.cfg on the installed version, matches the running gromox release. If there is a mismatch, fix loopback, service state and gromox configuration before chasing Keycloak claims.
2.13 Reboot and persistence test
Finally, reboot the appliance and repeat the core checks. SSO is only accepted when services, nginx, discovery, and web login work after reboot without manual intervention.
# Run on the grommunio appliancesystemctl reboot# After reconnectingsystemctl is-active grommunio-keycloak nginx php-fpm mariadb gromox-http gromox-zcorecurl -k -I https://mail.example.test/auth/realms/grommunio/.well-known/openid-configurationcurl -k -I https://mail.example.test/web/
2.12 Final login test with grommunio Web
The auth test does not end with a Keycloak token. Practical acceptance uses the full user path: open https://mail.example.test/web/, redirect to grommunio-auth/Keycloak, log in, complete MFA if required, redirect back to grommunio Web, see the mailbox and log out. Only that return path counts as end-to-end erfüllt.
✓ grommunio Web before login: Protected areas redirect to the intended login path.
✓ Keycloak/grommunio-auth login: The user can sign in to the grommunio realm.
✓ MFA: A required action or MFA policy is requested when enabled.
✓ Redirect back to grommunio Web: After successful login, the user returns to the web client.
✓ Mailbox visible: The mailbox is reachable after login.
✓ Logout: Signing out ends the session traceably.
Result Validation / Technical Acceptance
| Test area | Check | Expected result | Status |
|---|---|---|---|
| Installation | Check packages and components | The component is fully installed | PASS |
| Services | Check systemd services | The required services are active | PASS |
| Network | Check ports and URLs | The component is reachable through the intended paths | PASS |
| Core function | Run standalone test | The core function works before deeper integration | PASS |
| Authentication | Test SSO/login | Login works through the intended path or is intentionally not required | PASS or N/A |
| grommunio Web | Check integration from Web | The component is reachable or usable from grommunio Web | PASS or N/A |
| End-to-end | Test real user workflow | The full workflow is reproducibly successful | PASS |
| Restart | Restart services | The function remains available after service restart | PASS |
| Logs | Check relevant logs | No blocking errors in the validated flow | PASS |
Installation
- Check
- Check packages and components
- Expected result
- The component is fully installed
- Status
- PASS
Services
- Check
- Check systemd services
- Expected result
- The required services are active
- Status
- PASS
Network
- Check
- Check ports and URLs
- Expected result
- The component is reachable through the intended paths
- Status
- PASS
Core function
- Check
- Run standalone test
- Expected result
- The core function works before deeper integration
- Status
- PASS
Authentication
- Check
- Test SSO/login
- Expected result
- Login works through the intended path or is intentionally not required
- Status
- PASS or N/A
grommunio Web
- Check
- Check integration from Web
- Expected result
- The component is reachable or usable from grommunio Web
- Status
- PASS or N/A
End-to-end
- Check
- Test real user workflow
- Expected result
- The full workflow is reproducibly successful
- Status
- PASS
Restart
- Check
- Restart services
- Expected result
- The function remains available after service restart
- Status
- PASS
Logs
- Check
- Check relevant logs
- Expected result
- No blocking errors in the validated flow
- Status
- PASS
4. Common issues & troubleshooting
Wrong realm
Symptom: the client appears to exist, but grommunio Web does not redirect correctly or cannot find the client. Cause: work was done in the master realm. Fix: select grommunio in the realm selector and check Clients, User Federation, Authentication, and Identity Providers there.
Redirect URI mismatch
Symptom: Keycloak reports invalid_redirect_uri. Cause: browser URL, nginx, and client configuration do not use the same FQDN. Fix: align Root URL, Home URL, Valid Redirect URIs, and /etc/gromox/keycloak.json to the same public FQDN.
Client secret wrong or unreadable
Symptom: invalid_client or a login loop. Cause: wrong secret in /etc/gromox/keycloak.json or file permissions that prevent grommunio Web from reading it. Fix: copy the secret again from the Credentials tab, set the file to root:groweb 0640, and restart services.
Broker logout ends on a Keycloak page
Symptom: after logout through the upstream identity provider, the user does not return to grommunio Web. Fix: place the nginx redirect for /auth/realms/grommunio/broker/<alias>/endpoint/logout_response in the grommunio vhost, run nginx -t, and reload nginx.
5. Conclusion & next steps
The result is a production-ready SSO foundation for grommunio: Keycloak runs behind nginx, the grommunio realm contains client, federation, MFA flow, and optional broker configuration, and grommunio Web can authenticate users centrally.
The next logical step in the series is the targeted SSO integration of individual grommunio components such as Meet, Chat, and Files. Each component should get its own client, redirects, and acceptance check so the setup stays maintainable.
Continue with:grommunio Meet 2026 step by step,operating grommunio Chat for teams and tenants, andintegrating grommunio Files and Office.








