Migration

Migrating from Keycloak

Move users and applications from Keycloak to auth-service with the Keycloak compatibility profile and the migrate:keycloak command, keeping PBKDF2 passwords.

The plan is the one of the Okta guide: OIDC to OIDC, an instance profile, users imported with their ids, then a dual-issuer period. This page lists what is specific to Keycloak.

Configure the instance

COMPAT_PROFILE=keycloak

Tokens are signed with RS256, a request without resource yields a JWT for the application url, and tokens carry groups (with the roles scope) and preferred_username (with profile). Keycloak's own endpoint paths are not aliased: configure clients with the discovery URL https://auth.example.com/.well-known/openid-configuration. See Compatibility profiles.

What changes

In KeycloakIn auth-service
RealmThe whole instance. Users are global and each application grants them access. Several realms with overlapping users need merging (the e-mail is the unique key) or separate instances
Issuer https://kc/realms/<realm>https://auth.example.com
Endpoints under /protocol/openid-connect/The /api/auth/… endpoints; keys at /api/auth/jwks
Realm and client roles in realm_access.roles and resource_access.<client>.rolesThe application's roles, in the flat roles claim (and groups with the profile)
Client scopes and mappersRoles, permissions, plans, claim mappings; the scope list is fixed
aud set by an audience mapperaud is the requested resource, or the application url by default
Client secret: Basic or POSTHTTP Basic, unless TOKEN_ENDPOINT_AUTH_METHOD=post
User federation (LDAP, Kerberos), SAML clients, UMA / authorization services, token exchangeNot available. Social login is limited to Google and GitHub

Move the users

Export the realm with its users, for example kc.sh export --realm <realm> --users realm_file --file realm-export.json (the admin console's partial export does not include users), then:

pnpm migrate:keycloak -- --file realm-export.json --app acme-app            # dry run
AUTH_SERVICE_URL=https://auth.example.com ADMIN_EMAIL=… ADMIN_PASSWORD=… \
  pnpm migrate:keycloak -- --file realm-export.json --app acme-app --apply

The command reads the users with their ids, verified flag and PBKDF2 credentials (pbkdf2-sha256 and pbkdf2-sha512), which are imported so that users keep their password (it is re-hashed natively at their first sign-in). Groups become roles (the last segment of the group path, normalised into a role name); users without groups use their realm roles, without the built-in ones (default-roles-*, offline_access, uma_authorization). Service accounts and users without an e-mail address are skipped. A credential in another algorithm (for example argon2) is reported as unsupported-hash: those users reset their password. The options, the environment variables, the superadmin requirement and the report are those of the Okta command, except that --file is required and --trust-email defaults to true here: it marks as verified the addresses that the export says are verified (emailVerified).

The export contains password hashes: delete it when the migration is done.

Copyright © 2026