You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Admin CLI: log in with the Device Authorization Grant instead of the password grant?
#53822
When a person logs in with kcadm.sh config credentials --user <name>, both kcadm and kcreg send their username and password to the token endpoint using the Resource Owner Password Credentials grant (grant_type=password). The shared AuthUtil.getAuthTokens*() code does this, and the built-in admin-cli client therefore gets directAccessGrantsEnabled=true in every realm (RealmManager.setupAdminCli()).
This causes a few problems:
The grant is forbidden by current best practice.RFC 9700 (OAuth 2.0 Security BCP) says the password grant "MUST NOT be used", and OAuth 2.1 drops it entirely. Keycloak's main administration tool depends on it, and every realm ships with a client that has it switched on.
It skips the realm's authentication flow. Users with OTP, WebAuthn/passkeys or other second factors, and admins who sign in through an identity provider, can't use kcadm interactively. The CLI never sends a second factor, and an external IdP can't take part in a password grant. In practice, people either create admin accounts without MFA for CLI use or create service accounts with broad permissions.
The CLI sees the password. It is typed into the CLI, often handed over through KC_CLI_PASSWORD or --password, and from there it can end up in shell history and process lists.
It blocks a ROPC feature flag.Path forward for deprecating ROPC/Direct Access Grants in Keycloak? #24585 discusses putting ROPC behind a feature flag, and a maintainer comment there supports the idea. As long as the CLI needs ROPC, disabling it would break interactive kcadm logins. The same discussion already suggests device auth for kcadm.
$ kcadm.sh config credentials --server https://kc.example.com --realm master
Open https://kc.example.com/realms/master/device and enter code: WDJB-MJHT
(or open https://kc.example.com/realms/master/device?user_code=WDJB-MJHT)
Waiting for authorization...
Logged into https://kc.example.com as admin of realm master
The CLI requests a device code, shows the verification URI and user code, and polls the token endpoint until the user has finished logging in through the browser. Everything after that (refresh token, config file, ensureToken()) works as it does today.
Why the device grant rather than authorization code + PKCE with a loopback redirect (RFC 8252):
It works where kcadm is typically run: over SSH, inside containers, in kubectl exec sessions, and on hosts with no browser. The browser can be on any other device.
The full browser flow runs, so MFA, passkeys, identity brokering, required actions and brute-force protection all apply.
Keycloak already supports it: the DEVICE_FLOW feature is enabled by default, and admin-cli is a public client, which RFC 8628 is designed for. The only thing missing is oauth2.device.authorization.grant.enabled=true on admin-cli.
Non-interactive use (scripts, CI, operators) is unaffected. It should keep using client credentials (--client/--secret/--keystore), which kcadm already supports.
Scope for 27.0
There is no further minor release before 27.0, so a gradual rollout across releases isn't possible. As a major release, 27.0 is the place for a breaking default change like this one, so everything would land there in one step:
CLI:config credentials without --user, --secret or --keystore starts the device login. Today, that call only saves --server and --realm; that behaviour goes away.
New realms:admin-cli is created with the device grant enabled and direct access grants disabled.
Existing realms: a migration enables the device grant on admin-cli. Direct access grants are left as they are, so existing scripts and logins keep working after the upgrade (see open question 8).
--user/--password: still supported, but deprecated with a warning. They only work against an admin-cli client (or a custom --client) that still has direct access grants enabled. Removal could follow in a later major release (see open question 7).
Docs: the admin CLI guide switches to the device login, and the upgrading guide describes the changed defaults and how to re-enable direct access grants on admin-cli if needed.
Open questions
Explicit flag: should there also be an explicit --device option, for example to force the device login when a client ID is set?
Existing realms: is enabling the device grant on existing admin-cli clients through a migration acceptable, or should admins opt in? setupAdminCli() only configures the client when it creates it.
--no-config mode: with the password grant, each call logs in non-interactively. With the device grant, every call would need someone in a browser. Should the device grant require a config file, and should --no-config stay limited to client credentials and --user/--password?
Phishing: RFC 8628 §5.4 describes remote phishing with device codes. Should the verification page for admin-cli show extra context (client, requesting IP), or ask for explicit consent?
Feature disabled: if DEVICE_FLOW is disabled on a server, should the CLI fall back to the password grant (with a warning) or fail with a clear error?
Bootstrap: with direct access grants disabled on admin-cli in a new master realm, the documented first login (--user admin right after --bootstrap-admin-*) no longer works. Is the device login acceptable there, should master's admin-cli keep direct access grants for now, or should headless setups use the bootstrap service account (--bootstrap-admin-client-id/--bootstrap-admin-client-secret)?
Minor, but worth settling before implementation:
Password login in the CLI: should --user/--password stay in 27.0 as deprecated and be removed in a later major release, or be removed from the CLI in 27.0 already?
Direct access grants on existing realms: should the migration leave direct access grants on existing admin-cli clients untouched, or disable them as well, so existing realms end up in the same state as new ones?
Feedback on the general direction is welcome. Once the direction is clear I'd turn this into an enhancement issue.
Generative AI disclosure
This text was drafted with Claude Code (Anthropic). The AI went through the current kcadm/kcreg authentication code (AuthUtil, BaseConfigCredentialsCmd), the admin-cli client defaults in RealmManager, the DEVICE_FLOW feature and the related discussion #24585, and wrote this proposal from those findings. I reviewed and verified the content before posting.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Problem
When a person logs in with
kcadm.sh config credentials --user <name>, bothkcadmandkcregsend their username and password to the token endpoint using the Resource Owner Password Credentials grant (grant_type=password). The sharedAuthUtil.getAuthTokens*()code does this, and the built-inadmin-cliclient therefore getsdirectAccessGrantsEnabled=truein every realm (RealmManager.setupAdminCli()).This causes a few problems:
kcadminteractively. The CLI never sends a second factor, and an external IdP can't take part in a password grant. In practice, people either create admin accounts without MFA for CLI use or create service accounts with broad permissions.KC_CLI_PASSWORDor--password, and from there it can end up in shell history and process lists.kcadmlogins. The same discussion already suggests device auth forkcadm.Proposal
With Keycloak 27.0, make the OAuth 2.0 Device Authorization Grant (RFC 8628) the default interactive login method for
kcadm(andkcreg, which shares the same login code):The CLI requests a device code, shows the verification URI and user code, and polls the token endpoint until the user has finished logging in through the browser. Everything after that (refresh token, config file,
ensureToken()) works as it does today.Why the device grant rather than authorization code + PKCE with a loopback redirect (RFC 8252):
kcadmis typically run: over SSH, inside containers, inkubectl execsessions, and on hosts with no browser. The browser can be on any other device.DEVICE_FLOWfeature is enabled by default, andadmin-cliis a public client, which RFC 8628 is designed for. The only thing missing isoauth2.device.authorization.grant.enabled=trueonadmin-cli.Non-interactive use (scripts, CI, operators) is unaffected. It should keep using client credentials (
--client/--secret/--keystore), whichkcadmalready supports.Scope for 27.0
There is no further minor release before 27.0, so a gradual rollout across releases isn't possible. As a major release, 27.0 is the place for a breaking default change like this one, so everything would land there in one step:
config credentialswithout--user,--secretor--keystorestarts the device login. Today, that call only saves--serverand--realm; that behaviour goes away.admin-cliis created with the device grant enabled and direct access grants disabled.admin-cli. Direct access grants are left as they are, so existing scripts and logins keep working after the upgrade (see open question 8).--user/--password: still supported, but deprecated with a warning. They only work against anadmin-cliclient (or a custom--client) that still has direct access grants enabled. Removal could follow in a later major release (see open question 7).admin-cliif needed.Open questions
--deviceoption, for example to force the device login when a client ID is set?admin-cliclients through a migration acceptable, or should admins opt in?setupAdminCli()only configures the client when it creates it.--no-configmode: with the password grant, each call logs in non-interactively. With the device grant, every call would need someone in a browser. Should the device grant require a config file, and should--no-configstay limited to client credentials and--user/--password?admin-clishow extra context (client, requesting IP), or ask for explicit consent?DEVICE_FLOWis disabled on a server, should the CLI fall back to the password grant (with a warning) or fail with a clear error?admin-cliin a newmasterrealm, the documented first login (--user adminright after--bootstrap-admin-*) no longer works. Is the device login acceptable there, shouldmaster'sadmin-clikeep direct access grants for now, or should headless setups use the bootstrap service account (--bootstrap-admin-client-id/--bootstrap-admin-client-secret)?Minor, but worth settling before implementation:
--user/--passwordstay in 27.0 as deprecated and be removed in a later major release, or be removed from the CLI in 27.0 already?admin-cliclients untouched, or disable them as well, so existing realms end up in the same state as new ones?Feedback on the general direction is welcome. Once the direction is clear I'd turn this into an enhancement issue.
Generative AI disclosure
This text was drafted with Claude Code (Anthropic). The AI went through the current
kcadm/kcregauthentication code (AuthUtil,BaseConfigCredentialsCmd), theadmin-cliclient defaults inRealmManager, theDEVICE_FLOWfeature and the related discussion #24585, and wrote this proposal from those findings. I reviewed and verified the content before posting.All reactions