Skip to content

Repository files navigation

Spatial AI Keycloak authentication

This repository runs the shared Keycloak identity server used by Spatial AI applications. It also contains the OpenTech DB realm and its Go backend-for-frontend (BFF), which keeps Keycloak tokens in Redis and gives the browser only opaque, HttpOnly session cookies.

Application browser -- same-origin auth path --> application auth/BFF
                                                    |          |
                                      tokens in Redis          |
                                                    |          v
                                                    +----> Keycloak
                                                          app realm

The important boundary is: the Keycloak server may be shared, but application realms, clients, roles, secrets, redirect URIs, sessions, and BFF instances must not be shared by default. This repository currently provisions only the opentechdb realm and opentechdb-auth confidential client.

What is included

  • Keycloak 26 with PostgreSQL persistence.
  • The isolated opentechdb realm, its client, user profile, and roles.
  • The OpenTech Go auth service and Redis-backed server-side sessions.
  • A local Compose stack for development.
  • An nginx-fronted Compose stack for remote deployment, by IP or by DNS name.

The Go auth service is not yet application-neutral. Registration assigns the OpenTech contributor role, and returned roles are restricted to contributor and admin. Another application can share this Keycloak deployment, but must use its own realm/client and either standard OIDC integration or a separately configured/adapted BFF.

Local quick start

Prerequisites are Docker with Compose v2, GNU Make, and OpenSSL.

git clone https://github.com/THD-Spatial-AI/keycloak-auth.git
cd keycloak-auth
make install

make install creates a mode-600, gitignored .env.local, generates each secret independently, and starts PostgreSQL, Redis, Keycloak, the realm initializer, and the Go auth service. It never replaces an existing secret.

Local services:

Service URL
Keycloak http://localhost:8080
Admin Console http://localhost:8080/admin/
OpenTech auth API http://localhost:8001/api
Health endpoint http://localhost:8001/api/health

The local admin username is admin; its generated password is in .env.local. There is no default OpenTech application user.

Useful commands:

make dev          # start or rebuild the local stack
make dev-check    # verify .env.local matches the persisted database
make dev-reset CONFIRM=delete-local-keycloak-data  # delete disposable local auth data
make dev-status   # show container health/status
make dev-logs     # follow Keycloak and auth-service logs
make dev-down     # stop containers without deleting volumes
make test         # run all Go tests

make dev performs the credential check before Keycloak starts. If an older .env.local must be preserved, restore the complete file so its database, administrator, and client secrets stay consistent. The guarded dev-reset target deletes the local Keycloak database and Redis sessions only when the exact confirmation value is supplied.

Using this repository as an application submodule

An application can pin this repository at keycloak/:

git submodule add https://github.com/THD-Spatial-AI/keycloak-auth.git keycloak
git submodule update --init --recursive

Clone an application together with the pinned auth version using:

git clone --recurse-submodules <application-repository-url>

For an existing clone:

git submodule update --init --recursive

The parent application should run that update before invoking Compose. To upgrade deliberately, update and review the auth repository first, then commit the new submodule pointer in the application:

git -C keycloak fetch origin
git -C keycloak checkout <reviewed-commit-or-tag>
git add keycloak

Never make a parent application track an unpinned remote branch at runtime.

Connecting another application

1. Choose an isolation model

Use one realm per application unless shared accounts and single sign-on are an explicit product requirement. For example:

https://auth.example.org/realms/opentechdb
https://auth.example.org/realms/enerplanet
https://auth.example.org/realms/storcito

Separate realms prevent accidental sharing of users, passwords, sessions, roles, identity providers, and client configuration. Even when applications intentionally share a realm, each application still needs its own client.

2. Create the realm and client

Create the realm in the Admin Console or add a reviewed realm export under realm/ with an idempotent initialization step. Create an OpenID Connect client with:

  • a unique client ID;
  • exact HTTPS redirect URIs and web origins (no production wildcards);
  • Authorization Code flow;
  • a confidential client and secret when a server/BFF performs the exchange;
  • a public client with Authorization Code + PKCE when there is no trusted backend (never put a client secret in browser code);
  • only the scopes and role claims the application actually consumes.

The standard endpoints are discovered from:

https://<auth-host>/realms/<realm>/.well-known/openid-configuration

Typical server-side settings are:

OIDC_ISSUER=https://<auth-host>/realms/<realm>
OIDC_CLIENT_ID=<application-client-id>
OIDC_CLIENT_SECRET=<server-only-secret>
OIDC_REDIRECT_URI=https://<application-host>/auth/callback

Validate the token signature using the discovery/JWKS metadata and validate at least iss, aud/authorized party, exp, and authorization state/nonce as appropriate. Map only explicitly allowed roles into application permissions.

3. Prefer a same-origin BFF for browser applications

The OpenTech pattern keeps access and refresh tokens out of JavaScript:

Browser /auth-api/* --> application reverse proxy --> Go auth /api/*
Application backend -------------------------------> /internal/validate-session

The browser stores only session_id (HttpOnly) and a CSRF cookie. The application backend validates a session server-to-server with a different, 32-or-more-character AUTH_INTERNAL_SECRET sent as X-Internal-Auth.

For OpenTech DB the relevant application settings are:

VITE_AUTH_API_BASE_URL=/auth-api
AUTH_SERVICE_URL=https://<auth-host>
AUTH_REALM=opentechdb
AUTH_INTERNAL_SECRET=<same-value-as-the-OpenTech-auth-service>
OPENTECHDB_AUTH_UPSTREAM=https://<auth-host>

The application proxy maps /auth-api/* to the auth server's /api/*. The callback remains on the application origin:

https://<application-host>/auth-api/auth/callback

For another application, deploy a separate BFF endpoint and Redis namespace or database, use a separate internal secret, and adapt the current OpenTech role and registration policy. Do not route multiple apps to the existing OpenTech-specific /api/* service.

4. Verify the connection

Before enabling sign-in, verify:

  • discovery metadata is reachable over HTTPS;
  • the issuer exactly matches the application's configured realm;
  • redirect URI and web origin are exact matches;
  • the client secret exists only on trusted servers;
  • logout revokes the server session and clears cookies;
  • one realm's identity and roles are rejected by every other application;
  • /internal/*, PostgreSQL, and Redis are not publicly reachable.

VM deployment

The first command creates .env.vm, generates independent secrets, detects the VM address, and then stops so the application-server addresses can be reviewed:

make prod
$EDITOR .env.vm
make prod

The default VM stack uses plain HTTP and is intended only for a trusted test network. AUTH_APP_ENV=production creates Secure session cookies and therefore requires an HTTPS application origin for browser login. Never expose the HTTP variant directly to the public internet.

make prod verifies that .env.vm still authenticates to the persistent PostgreSQL volume before starting Keycloak, Redis, the OpenTech Go auth service, and nginx. Keep .env.vm backed up with the PostgreSQL volume: the database password, Keycloak administrator password, and OpenTech client secret are one persistent credential set.

make prod-logs
make prod-down

Persistent credential mismatch

POSTGRES_PASSWORD affects only the first initialization of a PostgreSQL data volume. Recreating .env.vm while retaining an older volume therefore cannot change the database login, Keycloak administrator, or realm-client secrets. make prod detects this condition before Keycloak enters a restart loop.

If the deployment contains users or realm configuration, restore the complete original .env.vm from backup. Do not change only KEYCLOAK_DB_PASSWORD, because the administrator and application-client secrets must match too.

For a new or disposable deployment, intentionally recreate the persistent data:

make prod-reset CONFIRM=delete-all-keycloak-data

This deletes all Keycloak realms/users in the Compose PostgreSQL volume and all Redis sessions. It does not run without the exact confirmation value.

Production secrets belong in a secrets manager or an uncommitted file with restricted permissions. Back up the Keycloak PostgreSQL volume. Redis contains active sessions; losing it logs users out but does not delete Keycloak users.

OpenTech identity-provider callbacks

Optional GitHub and ORCID providers are configured in the opentechdb realm with aliases github and orcid. Their provider-side callback is Keycloak's broker endpoint:

https://<auth-host>/realms/opentechdb/broker/<alias>/endpoint

Provider secrets stay in Keycloak and never enter the frontend repository.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages