P3.2: Enable password grant on local-llm Authentik provider #6

Closed
opened 2026-09-08 03:54:58 +00:00 by rock · 0 comments
Owner

Summary

Update local-llm OAuth2 provider in Authentik to support password grant type, bound to the headless authentication flow (no MFA/consent stages).

Why

/auth/token gateway endpoint needs to exchange username+password for JWT via Authentik. Current local-llm provider only has authorization_code + refresh_token grants. Password grant against the default flow fails because of MFA/consent stages.

Changes (in homelab repo, not homelab-frontend)

scripts/iam/authentik-provision.py

# Change local-llm grant_types from:
grant_types = ["authorization_code", "refresh_token"]
# To:
grant_types = ["authorization_code", "refresh_token", "password"]

Add authentication_flow: SA_AUTHENTICATION_FLOW_PK to local-llm provider (same headless flow service accounts use: identification → password → login, no MFA).

Add roles and permissions scope mappings to local-llm provider property_mappings so issued JWTs contain capability claims.

Verification

# After running authentik-provision.py:
curl -X POST https://authentik.riotpiao.com/application/o/token/ \
  -d "grant_type=password" \
  -d "client_id=local-llm" \
  -d "client_secret=$SECRET" \
  -d "username=rock" \
  -d "password=$PASS" \
  -d "scope=openid roles permissions"

# Should return: {"access_token":"eyJ...", "refresh_token":"...", ...}
# Decoded JWT should have: roles OR permissions claim with llm:inference

Review checklist

  • Headless flow bound (not default flow with MFA)
  • Scope mappings include roles + permissions
  • Re-running provision script is idempotent (patch_existing)
  • client_secret not rotated on re-run
  • Tested with wrong password returns proper error (not 500)
## Summary Update `local-llm` OAuth2 provider in Authentik to support `password` grant type, bound to the headless authentication flow (no MFA/consent stages). ## Why `/auth/token` gateway endpoint needs to exchange username+password for JWT via Authentik. Current `local-llm` provider only has `authorization_code` + `refresh_token` grants. Password grant against the default flow fails because of MFA/consent stages. ## Changes (in homelab repo, not homelab-frontend) ### `scripts/iam/authentik-provision.py` ```python # Change local-llm grant_types from: grant_types = ["authorization_code", "refresh_token"] # To: grant_types = ["authorization_code", "refresh_token", "password"] ``` Add `authentication_flow: SA_AUTHENTICATION_FLOW_PK` to local-llm provider (same headless flow service accounts use: identification → password → login, no MFA). Add `roles` and `permissions` scope mappings to `local-llm` provider property_mappings so issued JWTs contain capability claims. ### Verification ```bash # After running authentik-provision.py: curl -X POST https://authentik.riotpiao.com/application/o/token/ \ -d "grant_type=password" \ -d "client_id=local-llm" \ -d "client_secret=$SECRET" \ -d "username=rock" \ -d "password=$PASS" \ -d "scope=openid roles permissions" # Should return: {"access_token":"eyJ...", "refresh_token":"...", ...} # Decoded JWT should have: roles OR permissions claim with llm:inference ``` ## Review checklist - [ ] Headless flow bound (not default flow with MFA) - [ ] Scope mappings include roles + permissions - [ ] Re-running provision script is idempotent (patch_existing) - [ ] client_secret not rotated on re-run - [ ] Tested with wrong password returns proper error (not 500)
rock added this to the Phase 3: OAuth2 Token Exchange & Identity Propagation milestone 2026-09-08 03:54:58 +00:00
rock added the area/authentiktype/infrastatus/todopriority/high labels 2026-09-08 03:54:59 +00:00
rock self-assigned this 2026-09-08 03:55:00 +00:00
rock added this to the (deleted) project 2026-09-08 04:37:12 +00:00
rock closed this issue 2026-09-08 04:44:59 +00:00
Sign in to join this conversation.