AuthGeek

Systems, Security, & Architecture

Every User Starts as a Machine: Progressive Identity with APISIX and Keycloak

Anonymous visitors aren't ungated — they're machine-credentialed. Here's how APISIX and Keycloak implement progressive identity, tracking every user from their first anonymous request through full OIDC authentication.

For: Platform engineers, API gateway teams, and anyone who’s ever asked “what do we know about users before they log in?”

Every User Starts as a Machine

There’s a common architectural mistake that most teams make on their public-facing pages: they classify users as either “authenticated” or “anonymous” — and treat anonymous as meaning “unknown, untracked, ungated.”

The better mental model: every visitor is already in a trust context the moment they hit your gateway. The question is whether that trust context is machine-issued or user-issued.

This post walks through the progressive identity pattern — a design where anonymous visitors receive a narrow-scoped machine credential automatically, and the gateway tracks the precise moment their identity transitions from machine-issued to human-verified.

The Problem with Binary Authentication

Most API gateways gate on a single question: Does this request carry a valid user token?

If yes → forward. If no → redirect to login.

This leaves a massive blind spot. What do you know about the user before they log in? Where did they come from? What pages did they visit? At what point in the onboarding flow do users drop off?

The answer, with binary auth, is: nothing.

Not because the data doesn’t exist — but because you’ve provided no identity scaffolding for the unauthenticated phase of the journey.

Enter Progressive Identity

Progressive identity flips the assumption. Instead of “anonymous until authenticated,” the pattern is:

  1. Every visitor gets a machine credential — APISIX requests a short-lived client_credentials token from Keycloak’s token endpoint on behalf of the visitor. The token is scoped to the absolute minimum (read-only registration endpoints, 10-minute TTL, no refresh token). Open Policy Agent (OPA) enforces this scope at the gateway — even if someone were to present this machine token on a protected financial endpoint, OPA’s Rego policy would reject it because the token’s scope claim doesn’t include the required permission. The machine credential establishes a trust context the entire stack enforces, not just the application.
  2. The gateway tracks the session — APISIX mints a signed session_id and sets it as a cookie (HttpOnly; SameSite=Strict; Secure) on the visitor’s first request to /register. The HttpOnly flag prevents JavaScript from reading the cookie, closing the XSS vector.
  3. When the user authenticates, APISIX HMAC-signs the session_id and threads it into the OIDC state parameter of the redirect.
  4. After OIDC completes, Keycloak echoes the state back. APISIX verifies the signature, extracts the session_id, and the application layer can now correlate it to the newly-known user_sub.

The result: a complete, auditable identity timeline. Step 1 was anonymous. Step 7 was login. Everything in between is correlated.

What This Is Not

This is not an OAuth2 “token upgrade.” That concept doesn’t exist in the spec. A client_credentials token has no sub claim — it represents a machine acting on behalf of itself, not a user. A user OIDC token has a sub that represents a specific human being.

These are fundamentally different identity contexts. You cannot seamlessly convert one to the other — and you shouldn’t try. What you can do is create a correlation event at the moment of login: “the anonymous session abc123 just became the verified user user-uuid-456.”

That correlation event is actually the interesting architectural seam — and it’s what the AuthGeek demo visualizes in real time.

The Request Flow

sequenceDiagram
    participant Visitor as Anonymous Visitor
    participant APISIX as APISIX Gateway
    participant KC as Keycloak (IdP)
    participant App as Registration API

    Visitor->>APISIX: GET /register (no cookie)
    APISIX->>APISIX: Mint session_id, sign cookie
    APISIX->>KC: POST /token (client_credentials grant)
    KC-->>APISIX: machine_token (scope: registration, TTL: 10min)
    APISIX-->>Visitor: Set-Cookie: session_id=abc123 (signed)
    APISIX->>App: Proxy GET /register (X-Session-Id: abc123)
    App-->>Visitor: Registration page (machine-credentialed)

    Note over Visitor,App: User fills out form, clicks "Continue with Account"

    Visitor->>APISIX: GET /auth/login
    APISIX->>APISIX: Read session_id from cookie, sign into OIDC state param
    APISIX->>KC: 302 → /realms/demo/auth?state=signed(abc123)&...
    Visitor->>KC: Complete OIDC authentication
    KC-->>APISIX: Callback with code + state=signed(abc123)
    APISIX->>APISIX: Verify state signature, extract session_id
    APISIX->>App: POST /correlate {session_id: abc123, user_sub: user-uuid-456}
    App->>App: Log correlation event (immutable)
    APISIX-->>Visitor: Set user session cookie, redirect to /dashboard

The Security Constraints

A few non-negotiables that make this pattern safe:

The machine token is intentionally weak:

  • Scoped to registration endpoints only — OPA rejects any other route
  • 10-minute TTL, no refresh token
  • Even if leaked, it can’t authenticate as a user or access protected data

The session cookie is signed:

  • APISIX signs the session_id with HMAC before setting the cookie
  • The signature is verified on every subsequent request
  • A forged or tampered cookie is rejected before OPA processing

The OIDC state parameter is signed:

  • The session_id is HMAC-signed before being embedded in the OIDC state
  • Keycloak echoes the state unchanged; APISIX verifies the signature on callback
  • An attacker cannot inject a fake session_id to steal another user’s pre-auth history

The correlation event is immutable:

  • Once session_id → user_sub is logged, it cannot be altered
  • This creates an auditable trail from exact first anonymous request to authenticated user

Why Gateways, Not Applications

The tempting implementation is to handle all of this inside the registration application itself — mint tokens, track sessions, handle the OIDC redirect.

That’s the wrong layer.

When this logic lives in the gateway (APISIX), it works for every application that sits behind it — not just registration. A new partner onboarding flow, a free trial landing page, a public documentation portal — all of them get progressive identity scaffolding automatically, without a single line of application code.

That’s the Zero-Trust edge pattern in practice: security and identity management live at the perimeter, not in the business logic.

“Isn’t this just session management with extra steps?” It’s a fair question. Session cookies with IDs have existed since 2004. The difference: a plain session cookie is enforced by the application. A machine credential is enforced by the gateway — and by OPA at the policy layer. Every service behind APISIX gets this scaffolding automatically, without touching application code. The trust context is a first-class architectural primitive, not a database row in one app.

“What if the machine token expires during a long registration flow?” The machine token is not user-specific, which means APISIX can safely cache it at the gateway layer and transparently refresh it 30 seconds before expiry. From the user’s perspective, the session is seamless.

Important limitation: This pattern assumes a centralized API gateway. Applications that bypass APISIX don’t receive progressive identity scaffolding automatically — they’re on their own for session management.

What the Demo Shows

Open demo.authgeek.com/journey right now. Before you log in, you already have a machine credential. The XState visualizer shows you exactly what the gateway knows about you — before you know it too. Walk through the flow and watch the state transition from machine_credentialed to user_verified in real time, with the full correlation timeline visible at each step.


This is part of an ongoing series exploring the full Zero-Trust architecture: APISIX gateway, Keycloak IdP, and Open Policy Agent. The live demo environments are available at demo.authgeek.com.