Olympus Docs
Migration

From Keycloak

Migrating an existing Keycloak realm to Olympus

This guide moves a Keycloak realm to a self-hosted Olympus deployment.

Concept mapping

KeycloakOlympus
RealmCIAM or IAM domain (Olympus has two per deployment)
UserKratos identity
User attributesIdentity traits
Required actions (VERIFY_EMAIL, etc.)Kratos flow hooks / states
ClientHydra OAuth2 client
RoleIdentity trait (role: "admin"), Olympus doesn't have a separate role table
GroupIdentity trait (array of group names)
Identity provider (Google, GitHub, etc.)OIDC IdP configured per-domain in kratos.yml
Authentication flowKratos flow config
Authenticator (TOTP, WebAuthn)Kratos credential type
Account consoleKratos settings flow (rendered by Hera)
Admin consoleAthena
ThemesHera fork with your branding

Identity export → Kratos import

Step 1: Export from Keycloak

# Inside the Keycloak container or via kc.sh
./kc.sh export --dir /tmp/export --realm your-realm --users different_files

This produces JSON files: your-realm-realm.json (realm config), your-realm-users-N.json (users in chunks).

Step 2: Transform to Kratos identity format

Each Keycloak user → one Kratos identity:

{
  "schema_id": "default",
  "state": "active",
  "traits": {
    "email": "user@example.com",
    "name": { "first": "...", "last": "..." }
  },
  "verifiable_addresses": [
    { "value": "...", "verified": true, "via": "email", "status": "completed" }
  ],
  "credentials": {
    "password": {
      "type": "password",
      "identifiers": ["user@example.com"],
      "config": { "hashed_password": "$2a$10$..." }
    }
  }
}

Keycloak password hashes are typically pbkdf2-sha256 with embedded salt. Kratos supports importing pbkdf2 hashes, see Kratos's hash format docs. Map Keycloak's hash representation to Kratos's expected format.

If hashes can't be re-imported, fall back: force a password reset for every user via Kratos's recovery flow on first login.

Step 3: Bulk import

for f in identities-*.json; do
  curl -X POST http://localhost:3101/admin/identities -H 'content-type: application/json' -d @"$f"
done

OAuth2 client mapping

For each Keycloak client:

  • Public client (e.g. SPA) → Hydra public client with PKCE.
  • Confidential client (e.g. server-side app) → Hydra confidential client with client_secret_basic.
  • Bearer-only client (resource server) → no Hydra registration needed; validate tokens via introspection.
hydra create client \
  --endpoint http://localhost:3103 \
  --name <client-name> \
  --grant-type authorization_code,refresh_token \
  --response-type code \
  --scope "openid profile email" \
  --redirect-uri https://app.example.com/callback

Roles → trait

Keycloak's role concept doesn't have a direct Kratos equivalent. The typical Olympus pattern is:

"role": {
  "type": "string",
  "enum": ["admin", "operator", "user"]
}

For multi-role users, use an array trait. App code reads identity.traits.role to authorize.

Identity providers

Keycloak IdPs (Google, GitHub, etc.) become Kratos OIDC providers in kratos.yml:

selfservice:
  methods:
    oidc:
      enabled: true
      config:
        providers:
          - id: google
            provider: google
            client_id: <client-id>
            client_secret: <secret>
            mapper_url: file:///etc/config/kratos/oidc.google.jsonnet
            scope: ["openid", "email", "profile"]

Re-create the upstream Google/GitHub OAuth2 apps with Olympus's redirect URI.

Themes / branding

Keycloak themes don't port to Hera. Hera is a Next.js app, branding is a fork of Hera with your CSS/components.

Cutover patterns

Same as From Auth0: big-bang (downtime) or dual-write.

For Keycloak specifically, the dual-write pattern is harder because Keycloak's "user search" API is paginated and slow for large realms. Big-bang is usually preferred.

Things that don't directly map

  • Keycloak Authorization Services (UMA, fine-grained permissions), Olympus doesn't support. Implement in your app or via OPA / Cedar in front.
  • Keycloak Required Actions for custom flows, translate to Kratos hooks.
  • Keycloak SAML federation, Olympus is OIDC-first. For SAML, run a SAML→OIDC bridge.

Validation

  • User counts match.
  • Sample user can log in.
  • Social IdPs work.
  • Roles are visible in the ID token (Hydra includes traits).
  • Apps can validate access tokens.

On this page