Skip to content

Taskbase — Authentication

Overview

Taskbase uses Keycloak OIDC for authentication. The UI handles the browser login flow; the API validates Bearer JWTs on every request. Any user who is a member of the Skatzi Keycloak group gets full access — there is no role-based access control in v1 (see ADR 0003).

Authentication is optional at runtime: when the relevant environment variables are not set the entire auth layer is skipped. This is the intended behaviour for local development, where running a full Keycloak instance would be unnecessary overhead.


How it works

Browser                Keycloak              platform-tasks-ui        platform-tasks-api
   |                      |                         |                         |
   |-- OIDC login ------->|                         |                         |
   |<- JWT --------------|                         |                         |
   |-- load app ---------------------------------->|                         |
   |                                               |-- /api/* + Bearer JWT ->|
   |                                               |                         |-- verify JWT vs JWKS
   |                                               |                         |-- 401 if invalid
   |                                               |<- response -------------|
  1. The UI initialises keycloak-js with onLoad: 'login-required'. If the user has no active session, the browser is redirected to the Keycloak login page before the React app renders.
  2. After login, keycloak-js holds the access token and refreshes it automatically (when less than 30 seconds remain).
  3. Every API call from the UI includes Authorization: Bearer <token>.
  4. The API middleware (api/internal/auth) fetches Keycloak's JWKS via OIDC discovery and verifies the token signature and expiry. Requests without a valid token receive 401.
  5. /api/health is excluded from auth — it must remain reachable for Kubernetes liveness probes.

Environment variables

API (platform-tasks-api)

Variable Required in prod Purpose
KEYCLOAK_ISSUER Yes Full issuer URL, e.g. https://keycloak.prod.skatzi.com/realms/skatzi. When unset, the auth middleware is a no-op.

UI (platform-tasks-ui)

Variable Required in prod Purpose
VITE_KEYCLOAK_URL Yes Keycloak base URL, e.g. https://keycloak.prod.skatzi.com
VITE_KEYCLOAK_REALM No Realm name — defaults to skatzi
VITE_KEYCLOAK_CLIENT_ID Yes The Keycloak client ID registered for this app, e.g. taskbase

VITE_* variables are baked in at build time by Vite. They must be set in the build environment (CI/CD), not injected at runtime.

When both VITE_KEYCLOAK_URL and VITE_KEYCLOAK_CLIENT_ID are absent, the UI skips the OIDC flow entirely — no login page, no token, and the "Sign out" button is hidden.


Local development

No Keycloak setup is needed. Leave all auth variables unset (they are commented out in .env.example). The API will log:

auth: KEYCLOAK_ISSUER not set — running without authentication

and accept all requests without a token.


Keycloak client registration

A dedicated taskbase public client must exist in the skatzi realm. Add the following entry to components/keycloak/base/skatzi-realm.yaml under clients::

- clientId: taskbase
  name: "Taskbase"
  description: "Task management application"
  enabled: true
  publicClient: true
  standardFlowEnabled: true
  directAccessGrantsEnabled: false
  webOrigins:
    - "https://taskbase.prod.skatzi.com"
  redirectUris:
    - "https://taskbase.prod.skatzi.com/*"

This follows the same pattern as the existing skatzi-web client. PKCE (S256) is enforced by keycloak-js on the client side — no additional Keycloak configuration is required for it.


Testing auth locally (optional)

If you need to test the full OIDC flow locally, port-forward Keycloak and set the variables:

kubectl port-forward -n keycloak svc/keycloak-service 8081:8080

# .env
KEYCLOAK_ISSUER=http://localhost:8081/realms/skatzi

# ui/.env.local  (Vite picks this up automatically)
VITE_KEYCLOAK_URL=http://localhost:8081
VITE_KEYCLOAK_CLIENT_ID=taskbase

The taskbase client in Keycloak will also need http://localhost:5173/* added to its redirectUris for the Vite dev server to work.