Files
command-center/agent/managed-skills/authentik-session-ttl-query/SKILL.md
T
Frank 8af40c402b chore(agent): commit the machine tier and the doctrine text the checkout was already running
Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and
`merge --ff-only` refuses while tracked paths are dirty. Discard is not available here
(workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed.

- `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already
  byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new
  prose — the commit exists so the trunk merge can proceed.
- `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat
  owns (AGENTS.md § Live-sync tiers).

`ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the
only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the
inert all-zero AWS example id — and they appear inside the two skill pages that teach
that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged
gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal
dies with this landing. No `--no-verify` was used: the gate ran and its verdict is
recorded here.

Refs #61
2026-10-21 01:44:51 -07:00

3.6 KiB
Raw Blame History

name, description
name description
authentik-session-ttl-query Query or change authentik login-session TTL on Dankclaw via ak shell — the string-typed UserLoginStage.session_duration trap, the apply logic, and why SESSION_SAVE_EVERY_REQUEST is unavailable.

Change or audit how long an authentik login session lives (Dankclaw authentik-server, build 2026.x). The real knob is a DB stage row, not env — and the field format will bite you.

Where the TTL actually lives

  • Run program through raw stdin: ssh dankclaw 'podman exec -i authentik-server ak shell' <<'EOF' ... EOF 2>&1 | sed -n '/objects imported/,$p'.
  • Get models by label, NOT import paths (from authentik.core.models.setting import ... fails; authentik.core.models is not a package; GlobalSettings is NOT a model in 2026.x): from django.apps import apps; ULS = apps.get_model("authentik_stages_user_login", "UserLoginStage")
  • The password sign-in path is flow default-authentication-flow → stage default-authentication-login (FlowStageBinding FK is target, not flow). Other stages default-source-authentication-login / default-source-enrollment-login govern external-IdP/enrollment logins only.

THE FORMAT TRAP (will break login if wrong)

UserLoginStage.session_duration is string-typed in authentik's own idiom: "days=7" / "seconds=2".

  • Assigning a datetime.timedelta stores Python's str(timedelta) = '7 days, 0:00:00', which authentik's parser authentik.lib.utils.time.timedelta_from_string REJECTS (ValueError: not enough values to unpack). Left like that, login crashes computing the expiry.
  • Correct write: s.session_duration = "days=7"; s.save(update_fields=["session_duration"])
  • Verify it parses: from authentik.lib.utils.time import timedelta_from_string as P; P(s2.session_duration) → 7 days, 0:00:00. A single key=value token only; "days=7 seconds=0" also errors.

How it applies (stage.py:77-87, verified)

delta = timedelta_from_string(session_duration); if remember: delta += remember_me_offset; then set_expiry(0) if delta==0 else set_expiry(delta). So any positive duration applies to EVERY login (remember-me only adds on top), and set_expiry(<positive>) overrides SESSION_EXPIRE_AT_BROWSER_CLOSE → persistent cookie. Existing sessions keep their old expiry; new logins only.

SESSION_SAVE_EVERY_REQUEST (sliding window) is NOT available

/authentik/root/settings.py reads SESSION_COOKIE_AGE from CONFIG.get("sessions.unauthenticated_age","days=1"), sets SESSION_EXPIRE_AT_BROWSER_CLOSE=True, and references SESSION_SAVE_EVERY_REQUEST nowhere → no AUTHENTIK_* env or config.yml key can flip it. Enabling a sliding window means patching the vendor image; instead raise the login-stage duration (absolute, supported).

Audit the rest of the expiry surface (live values)

  • framework: settings.SESSION_COOKIE_AGE, SESSION_SAVE_EVERY_REQUEST
  • OAuth2 RPs: apps.get_model("authentik_providers_oauth2","OAuth2Provider") → access_token_validity / refresh_token_validity (this fleet: access 1h [embedded-outpost 24h], refresh 30d)
  • proxy claim cache: authentik_providers_proxy.ProxySession.expires (observed ~1–24h; silent re-auth, not a logout)
  • tenant: authentik_tenants.Tenant.default_token_duration (hand API tokens, not sessions)

Notes

  • These stage/provider rows are DB state, NOT repo-managed → a blueprint re-import or fresh rebuild reverts them; drop a setup script/blueprint in the repo if reproducibility matters.
  • Don't probe the guarded vhost for the agent API and don't confuse Anubis' 168h challenge cookie with the authentik login session.