From d055483aa2c1db19a1bb2c581ae41e4fcfc4845b Mon Sep 17 00:00:00 2001 From: Story Crater Bot <19826264+Riotpiaole@users.noreply.github.com> Date: Thu, 27 Aug 2026 11:51:02 -0700 Subject: [PATCH] feat: add poimen-memory as an Authentik service-to-service client Client credentials + device code grant, no browser redirect (empty redirect_uris) - unlike every other SERVICES entry which is authorization_code web SSO. First real step toward replacing poimen-memory's static API key with a proper JWT flow. --- k8s/infra/iam/scripts/authentik-provision.py | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/k8s/infra/iam/scripts/authentik-provision.py b/k8s/infra/iam/scripts/authentik-provision.py index 427ba97..c664c1c 100644 --- a/k8s/infra/iam/scripts/authentik-provision.py +++ b/k8s/infra/iam/scripts/authentik-provision.py @@ -415,6 +415,15 @@ SERVICES = { "launch_url": "https://vault.riotpiao.com", "display_name": "Vault", }, + "poimen-memory": { + # Service-to-service API auth (no browser redirect) - generate secret on first run. + "client_secret_source": ("poimen", "poimen-memory-oidc", "CLIENT_SECRET"), + "generate_if_missing": True, + "extra_secret_literals": {"client-id": "poimen-memory"}, + "redirect_uris": [], # No browser flow, service-to-service only + "launch_url": "https://memory.riotpiao.com", + "display_name": "Poimen Memory", + }, } app_pks_for_binding = [] @@ -501,6 +510,16 @@ for name, cfg in SERVICES.items(): "config.json": immich_config_json, }) + # Service-to-service (client_credentials): poimen-memory + # Browser SSO (authorization_code): all others + grant_types = [ + "urn:ietf:params:oauth:grant-type:device_code", # device code flow (CLI/headless) + "client_credentials" # service-to-service + ] if name == "poimen-memory" else [ + "authorization_code", # web SSO + "refresh_token" # long-lived sessions + ] + provider = get_or_create( "/api/v3/providers/oauth2/", "/api/v3/providers/oauth2/", f"name={name}", @@ -520,7 +539,7 @@ for name, cfg in SERVICES.items(): # every login with "Invalid grant_type for provider" -> # invalid_request. authorization_code = the web SSO flow all these # apps use; refresh_token = long-lived sessions (offline_access). - "grant_types": ["authorization_code", "refresh_token"], + "grant_types": grant_types, "redirect_uris": [ {"matching_mode": "strict", "url": u} for u in cfg["redirect_uris"] ], @@ -530,7 +549,7 @@ for name, cfg in SERVICES.items(): # truth in the k8s Secret, and re-sending it here is harmless anyway). patch_existing={ "property_mappings": provider_mappings, - "grant_types": ["authorization_code", "refresh_token"], + "grant_types": grant_types, "redirect_uris": [ {"matching_mode": "strict", "url": u} for u in cfg["redirect_uris"] ],