SpecsModelExplore
Overview
IOModel Stack
Reverse ProxyIOModel StudioYjs Realtime ServerKeycloakPostgreSQLRedis
Why it's needed
Deployment
SpecsModelExplore
Keycloak
OverviewKeycloak GuideLinks and Communications

Keycloak is the identity provider for the stack. It owns users, credentials, and sessions, and speaks OpenID Connect so Studio never has to store passwords itself.

Role in the stack

Studio delegates sign-in to Keycloak via OIDC. Keycloak can also federate to enterprise SSO (LDAP, SAML, social logins), making it the single place to manage identity.

Why it’s needed

  • No passwords in the app — authentication is delegated; Studio only trusts signed tokens.
  • SSO & federation — connect existing corporate identity providers.
  • Central policy — MFA, session lifetime, and password rules live here.

Optional component

Keycloak is bundled for convenience but is optional. You can point IOModel at any OIDC-compatible provider via AUTH_KEYCLOAK_ISSUER and related variables.

Deployment

Keycloak itself is stateful, but its state lives in a database — so the workload can be treated as a Deployment while a database holds the realm data.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  namespace: iomodel
spec:
  replicas: 1
  selector: { matchLabels: { app: keycloak } }
  template:
    metadata: { labels: { app: keycloak } }
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:latest
          args: ['start', '--optimized']
          env:
            - name: KC_DB
              value: postgres
            - name: KC_HOSTNAME
              value: iomodel.example.com
          ports: [{ containerPort: 8080 }]

Set KC_HOSTNAME (and KC_PROXY when behind the reverse proxy) to the public origin. A wrong hostname/issuer is the most common cause of redirect loops.

Change the default admin credentials

The imported iomodel realm ships with a default admin account (admin / admin). Rotate it before exposing the deployment.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  namespace: iomodel
spec:
  replicas: 1
  selector: { matchLabels: { app: keycloak } }
  template:
    metadata: { labels: { app: keycloak } }
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:latest
          args: ['start', '--optimized']
          env:
            - name: KC_DB
              value: postgres
            - name: KC_HOSTNAME
              value: iomodel.example.com
          ports: [{ containerPort: 8080 }]