Identity and OIDC

Authority model

Keycloak is the StoreMesh identity authority. It owns credentials, OIDC sessions, user access/refresh tokens, and platform roles. User Service owns customer profiles and domain data. New clients should not implement a second password authority.

There are currently two JWT paths during migration:

These tokens are not interchangeable. A valid Keycloak JWT cannot be verified with the legacy User Service JWT_SECRET, and a legacy User Service JWT is not a Keycloak OIDC token.

Client flow

The web, Android, and iOS clients use separate public Keycloak clients with Authorization Code + PKCE:

  1. The client creates a cryptographically random PKCE verifier and challenge.
  2. The system browser opens the Keycloak authorization endpoint.
  3. Keycloak redirects back with a short-lived authorization code.
  4. The client exchanges the code and verifier at the token endpoint.
  5. The client stores tokens in the browser session or platform-secure storage and sends the access token as Authorization: Bearer to the BFF.
  6. The BFF validates the Keycloak JWT signature using Keycloak JWKS, plus issuer, audience, expiry, and role claims, before making internal gRPC calls.

PKCE protects public clients because no client secret is shipped in browser or mobile binaries. Redirect URIs must be exact and separately registered for each client.

Local development

The local Helm realm is storemesh. The development clients and redirects are declared in the Helm chart; local passwords and client values are not suitable for shared environments. Android emulator builds use the host alias 10.0.2.2, while the iOS Simulator uses localhost:

Client Redirect Local issuer
Web http://localhost:3000/* http://localhost:8081/realms/storemesh
Android com.storemesh.android://oauth/callback http://10.0.2.2:8081/realms/storemesh
iOS storemesh-ios://oauth/callback http://localhost:8081/realms/storemesh

For a physical device, use HTTPS and a reachable issuer/API origin such as an authenticated ngrok tunnel. Never expose PostgreSQL, Redis, gRPC, or observability ports through the tunnel.

Downstream service activation

The BFF, Product, Order, and Inventory Helm charts all support the same config.keycloakIssuer and config.keycloakAudience settings. The Argo CD applications keep the issuer empty by default because Keycloak is an optional local dependency and the legacy-compatible smoke path must remain usable. When Keycloak is enabled, set the issuer to the exact URL used in the token's iss claim and use the storemesh-bff audience consistently. For an in-cluster-only path this is typically:

http://storemesh-keycloak.<namespace>.svc.cluster.local:8080/realms/storemesh

The ready-to-adapt values file is examples/service-keycloak-oidc-values.yaml. Apply the same values to all four Argo applications only after Keycloak health and realm discovery succeed. Public web/mobile clients must obtain tokens from an issuer reachable by those clients; an internal service DNS name cannot be used as their external issuer.

The optional Keycloak Argo CD Application is storemesh-keycloak-application.yaml. It is intentionally excluded from the default bootstrap and requires the storemesh-keycloak-admin Secret to be created outside Git.

The local realm import also adds a storemesh-bff audience mapper to the web, Android, and iOS clients' access tokens. This is required because signature validity alone does not prove that a token was issued for the BFF. If clients or a realm are created manually, reproduce that mapper and verify the decoded access token contains aud: storemesh-bff before enabling strict downstream validation.

Operations checklist

Service-to-service JWT

Order Service also has a separate machine-to-machine JWT option for calls to Product Service. It is signed with the Product Service shared secret and is unrelated to human OIDC access tokens. This is a transitional service-auth mechanism; production deployments should prefer Istio mTLS and/or workload identity, with authorization claims enforced at the receiving service.

Platform-tool SSO status

The local Keycloak realm import reserves clients for Grafana, Kiali, Kibana, and Argo CD, but client registration alone does not enable SSO. Each tool still requires an environment-specific OIDC configuration, callback URL, role mapping, and confidential client secret. The current local defaults are:

Tool Current local access OIDC rollout requirement
Grafana Local admin login Configure auth.generic_oauth, issuer, scopes, role mapping, and a Secret-backed client secret
Kiali Anonymous local access Change the Kiali auth strategy to OpenID and map approved roles
Kibana ECK-generated elastic user Configure the Elastic OIDC provider and callback settings with protected credentials
Argo CD Local admin credential Configure Argo CD Dex/OIDC, group claims, and admin role mapping

This staged approach keeps the disposable Kind cluster usable while avoiding committing secrets or accidentally changing access policy in a shared cluster. The activation order is Keycloak health and issuer discovery, tool callback and secret configuration, role-mapping verification, then removal or restriction of local fallback accounts. Record the result in the environment's deployment evidence before calling platform SSO complete.

Non-applied Grafana and Argo CD configuration examples are maintained in the storemesh-argocd-repo repository. They are templates only and require environment-specific issuer, HTTPS callback, secret, and role values before use.