Skip to content

feat(keycloak): make realm tokens usable by pyro-api and the scripts - #68

Draft
ThbltLmr wants to merge 4 commits into
feat/keycloakfrom
feat/keycloak-api-integration
Draft

ThbltLmr wants to merge 4 commits into
feat/keycloakfrom
feat/keycloak-api-integration

Conversation

@ThbltLmr

@ThbltLmr ThbltLmr commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #45. Makes the Keycloak realm from #45 usable by pyro-api, and moves the init script and notebooks off the superadmin password.

Needs the pyro-api Keycloak support (pyronear/pyro-api#728) to verify tokens. Until a release ships it, build the API image from that branch (make build-external).

Demo

Recorded against this stack with pyronear/pyro-api#728 and pyronear/new-pyro-platform#295. The bottom panel is a network log the recording script draws from the Chrome DevTools Protocol, since Chrome's own DevTools can't be captured in a headless recording.

Platform login through the realm: the redirect to the themed Keycloak login, the token with aud: pyro-api, top-level roles and organization_id, then the platform's API calls with that token (organization 2's cameras only). The first GET /alerts/unlabeled/latest gets a 401 because the platform sends it before attaching the token, a race in #295.

keycloak-platform-demo.mp4

Revocation through the pyro-api client: GET /login/validate with test77's token returns 200. An admin then signs test77 out in Keycloak, and the API's introspection call (as the pyro-api client) turns the same unexpired token into a 401.

keycloak-api-demo.mp4

Realm

  • New pyro-api client scope: adds pyro-api to aud and the realm roles as a top-level roles claim, which the platform PR already reads.
  • The pyro-organization claim is renamed from organization to organization_id. organization is the claim Keycloak's built-in Organizations feature writes, and that scope is already optional on the platform client.
  • new-pyro-platform gets both scopes by default.
  • New confidential pyro-api client with every login flow off. The API authenticates as it to introspect each token, so a revoked session fails on its next request.
  • New pyro-scripts service account (realm role admin, org 1). Its tokens last 10 hours, the realm's session maximum, because the scripts fetch one token per run.
  • New test-admin user (admin, org 1, password test).

Compose

  • Keycloak moves out of the tools profile, so make run-backend starts it.
  • KC_HOSTNAME=http://localhost:9310 gives every token the same issuer whether it was requested from the browser or from a container on keycloak:9310.
  • The healthcheck reads /health/ready on the management port. The old one grepped a server.log that Keycloak never writes, so it always reported unhealthy.
  • pyro_api gets KEYCLOAK_ISSUER, KEYCLOAK_BACKCHANNEL_URL and the pyro-api client secret.
  • init_script and notebooks get the pyro-scripts credentials, with defaults so a .env created before Keycloak still works. init_script waits for Keycloak to be healthy.

Scripts

  • get_service_token() (client credentials) replaces the superadmin login in the init script and the five notebooks.
  • The notebooks' old get_token() stays for local scripts while pyro-api still accepts API-issued user tokens.

How to test

  1. docker compose up -d --force-recreate keycloak. The realm only imports into a new container.
  2. Run the stack with the pyro-api branch and log in to the platform as test77 / test.
  3. Seed with init_script. It now authenticates through Keycloak.
  4. Log test77 out from the Keycloak admin console (http://localhost:9310/admin/). The platform's next API call should get a 401.

All secrets in the realm export are dev-only values.

Stack created with GitHub Stacks CLI • Give Feedback 💬

- pyro-api client scope: adds pyro-api to aud and the realm roles as a
  top-level roles claim
- pyro-organization claim renamed to organization_id, which avoids Keycloak's
  built-in Organizations claim
- new-pyro-platform gets both scopes by default
- pyro-api confidential client, used by the API to introspect tokens
- pyro-scripts service account (admin, org 1, 10h tokens) for the init script
  and notebooks
- test-admin user (admin, org 1)
…and scripts

- Keycloak leaves the tools profile, pins its issuer with KC_HOSTNAME and
  reports readiness from /health/ready
- pyro_api gets KEYCLOAK_ISSUER, the backchannel URL and the pyro-api client
  secret
- init_script and notebooks get the pyro-scripts credentials, with defaults
  for .env files created before Keycloak
The init script and notebooks use client credentials instead of logging in
with the superadmin password. The notebooks' legacy get_token stays for local
scripts while pyro-api still accepts API-issued user tokens.
@ThbltLmr
ThbltLmr added this pull request to stack #69 October 28, 2026 13:37
@ThbltLmr ThbltLmr changed the title feat/keycloak api integration feat(keycloak): make realm tokens usable by pyro-api and the scripts Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant