Skip to content
Updated Jun 9, 2026

Auth & Security

Olly uses Keycloak as its OpenID Connect provider. This page covers the identity and authorization model. For PHI handling, consent, erasure, and audit, see Data Protection.

Implemented vs designed

The identity model below (realm, clients, grants, JWT validation) is what runs today. The fine-grained authorization mesh (OPA/ABAC, service-mesh mTLS, PHI audit logging, multi-realm isolation) is draft design (see Designs → Access Control), not running. Sections are labelled accordingly.

Identity (implemented)

There is one realm, olly, on Keycloak at auth.dev.hiolly.com (container olly-keycloak, port 8093). Keycloak is fronted by nginx; APISIX (:9080) is the API gateway for the Go services. The access-token TTL is 15 minutes.

ClientGrantAppJWT claim
web-employerPKCE (auth code)employer SPA (Vite + React PWA)org_locator
web-memberROPC (password)member SPA (Vite + React)party_locator
web-admindirect grant / OIDCadmin console (Next.js)
web-providerpublicprovider portal
mobile-appdirect grantmobile

Not every flow is PKCE: the employer SPA uses PKCE, but the member and mobile clients use ROPC / direct grant (which is what makes the copy-paste token in the API Quickstart possible). Service-to-service calls use the client-credentials grant against the same token endpoint.

Auth flow per app (implemented)

  • Employer SPA: PKCE Authorization Code; the JWT carries org_locator to scope the request to one scheme.
  • Member SPA: ROPC: the app exchanges username/password for a token carrying party_locator.
  • Admin console (Next.js): Keycloak OIDC.
  • Mobile: direct grant.
  • Service-to-service: client credentials (e.g. the seeder gets an admin token this way).

The JWT's org_locator (employer) or party_locator (member) is the scoping claim every downstream check keys on.

JWT validation (implemented; finer authz is designed)

APISIX validates the bearer token (signature against the Keycloak JWKS, issuer, expiry) and forwards to the Go service, which re-validates as defence in depth (JWKS cached in-process). Beyond that coarse check, the fine-grained authorization layer is designed, not built: the OPA/ABAC policy checks, the per-resource member_id-matches checks, and service-mesh mTLS in the diagram below are roadmap items in Designs → Access Control, not running in the dev stack (which is Docker Compose on Hetzner with no service mesh).

Roles (intended model)

Roles live in the olly realm as Keycloak realm roles. The table is the intended model; enforcement today is coarse (gateway + claim scoping), with attribute-based enforcement (a member sees only their own resources, a provider only their patients) being the designed OPA/ABAC layer.

RoleSummary
MEMBERView/submit own claims, view coverage and EOBs, manage own enrollment
EMPLOYER_ADMINMEMBER scope for their group, manage group enrollment, billing overview
PROVIDERView claims for their patients, submit claims, view prior auth and credentialing
CLAIMS_ADJUSTERRead/adjudicate claims, decide prior auths, view member PHI (to be audit-logged)
UNDERWRITERActuarial data, rate tables, read-only claims aggregates
NETWORK_MANAGERProvider credentialing, network contracts, directory
SYSTEM_ADMINRealm administration, policy and secret management

Sessions (implemented)

Keycloak issues 15-minute access tokens with refresh-token rotation (each refresh issues a new token and invalidates the prior one; reuse of a stolen refresh token invalidates the session family). Re-authentication is forced on password change and at hard session expiry.

Designed, not yet built

These are in Designs → Access Control at draft status, with no running implementation:

  • Multi-realm isolation: separate realms per user population (members / providers / internal / services). Today it is the single olly realm.
  • OPA / ABAC: attribute-based authorization at the gateway and in-service (the per-resource and PHI-field checks).
  • Service-mesh mTLS and /internal/* mesh-only enforcement.
  • OpenBao-driven secret rotation for M2M client secrets.
  • PHI access logging and 6-year WORM audit retention: the CloudTrail/S3 Object Lock and OpenSearch-ILM retention described in older drafts targets an AWS/managed deployment; it is not running. See Data Protection for the real audit posture (consent-scoped only today).

Olly Health Insurance Platform