Add forte-cli public device-code Keycloak client

Add a shared public client `forte-cli` to the `forte` realm so downloaded
skills (forte-drop first) can do RFC 8628 device-code login through the
Auth Sidecar. Today no client in the realm has the device grant enabled,
so the flow cannot start.

Client (inline in forte-realm.json, imported verbatim by keycloak-config-cli):
- publicClient: true, standardFlowEnabled: false,
  directAccessGrantsEnabled: false
- attributes: oauth2.device.authorization.grant.enabled=true
- no secret, no redirectUris/webOrigins, no k8s.secret.sync

It has to go in the realm JSON because the self-service registrar
hardcodes publicClient:false/standardFlowEnabled:true and drops
attributes. Also add forte-cli to the cleanup CronJob's protected list
(belt-and-braces; it does not match the UUID pattern anyway).

Additive only: gitea/grafana/argocd and all other realm settings are
unchanged. Keycloak is deployed only via the upc-dev overlay, which
inherits base values, so this lands on id.forteapps.net.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciXev3MtCxo3eomcfrDRW
This commit is contained in:
Jørgen Stensrud
2026-10-01 10:37:12 +00:00
committed by danijel.simeunovic
co-authored by Claude Fable 5.1
parent 60b8fa657a
commit 0bf8c3988e
2 changed files with 22 additions and 1 deletions
+6
View File
@@ -1469,6 +1469,12 @@ ArgoCD will sync the Keycloak config, and the registrar CronJob will pick up the
| `k8s.secret.client-id-key` | No | `client-id` | Field name for the client ID in the K8s Secret |
| `k8s.secret.client-secret-key` | No | `client-secret` | Field name for the client secret in the K8s Secret |
#### Public CLI Client (Device-Code Login)
`forte-cli` is a shared **public** client (no secret) with the RFC 8628 device-authorization grant enabled (`oauth2.device.authorization.grant.enabled: "true"`, `standardFlowEnabled: false`, `directAccessGrantsEnabled: false`). Downloaded skills and CLI tools that log in through the Auth Sidecar (forte-drop first) use it with `<PREFIX>_CLIENT_ID=forte-cli`; nothing per-tool needs to be registered in Keycloak.
It must be defined in `forte-realm.json` (this legacy path): the self-service registrar hardcodes `publicClient: false` / `standardFlowEnabled: true` and drops `attributes`, so a `client-config` Secret cannot produce a public device-code client. It carries no `k8s.secret.sync` attribute (the registrar's secret sync skips it) and is listed in the cleanup CronJob's protected clients.
### Retrieving Secrets for External Deployments
The registrar always writes a **central copy** of every synced secret to the `secrets` namespace, in addition to the target namespace. This allows operators to retrieve client credentials for applications deployed outside this cluster: