From 4f50bfbb19c0f7eba7769080d0e3b41fe5ec2210 Mon Sep 17 00:00:00 2001 From: Alex Godbehere Date: Fri, 17 Jul 2026 15:12:32 +0100 Subject: [PATCH] service-setup: per-client accessTokenLifespan passthrough A values-declared client can now set accessTokenLifespan (seconds) to override the realm's 300s access-token lifespan via the client attribute access.token.lifespan. Needed for unattended kiosk consumers (Grafana url_login re-presents the JWT on every request, so the wall dies at exp): give the kiosk client a long lifespan and refresh before expiry. Co-Authored-By: Claude Opus 4.8 (1M context) --- acs-service-setup/lib/openid.js | 10 ++++++++++ deploy/values.yaml | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/acs-service-setup/lib/openid.js b/acs-service-setup/lib/openid.js index ee13fb3c0..6cb5dc921 100644 --- a/acs-service-setup/lib/openid.js +++ b/acs-service-setup/lib/openid.js @@ -294,6 +294,16 @@ class OpenIDSetup { ...(spec.deviceAuthorizationFlowEnabled ? { "oauth2.device.authorization.grant.enabled": "true" } : {}), + // Per-client access-token lifespan override, in seconds. + // Keycloak's realm default (300s) is right for API tokens + // but wrong for an unattended display credential: a kiosk + // JWT (e.g. Grafana url_login) is re-presented on every + // request and the wall dies at exp, so a kiosk client + // wants a long lifespan (days) and a refresh-before-expiry + // on the consumer side. Omit for the realm default. + ...(spec.accessTokenLifespan + ? { "access.token.lifespan": String(spec.accessTokenLifespan) } + : {}), }, }; if (secret !== undefined) desired.secret = secret; diff --git a/deploy/values.yaml b/deploy/values.yaml index a35280ec4..fe2127cfe 100644 --- a/deploy/values.yaml +++ b/deploy/values.yaml @@ -232,6 +232,13 @@ serviceSetup: # name: Polyptic kiosk # serviceAccountsEnabled: true # standardFlowEnabled: false + # + # `accessTokenLifespan` (seconds) overrides the realm's access-token + # lifespan (default 300s) for one client. A kiosk JWT is re-presented + # on every request by the consuming app (e.g. Grafana url_login), so + # an unattended display dies at token expiry: give such clients a + # long lifespan (e.g. 2592000 = 30 days) and let the consumer refresh + # before expiry. Leave unset everywhere a human signs in. openidClients: grafana: enabled: true