CodamAIDocs
Topicdone

Embedded and standalone compared

All differences between “CIAS in the same process” and “CIAS as a separate service” in one overview: artifacts, calls, database, failure behavior and the delay of a suspension.

Variants
embedded (a single unit)standalone (two services)CIAS reachable / not reachable

What this is about

CIAS can run next to CDMS in two ways. In the subject area, the result is always the same: same code, same rules, same rejections. The only difference is how CDMS and CIAS talk to each other.

The two pictures

flowchart LR
    subgraph E["Embedded: one process"]
        direction TB
        E_CDMS["CDMS / hub backend"]
        E_CIAS["CIAS modules<br/>(authentication, tenancy,<br/>user, authorization, …)"]
        E_CDMS <-->|method call| E_CIAS
    end
    E_DB[("System DB<br/>CDMS + CIAS tables")]
    E --> E_DB
    E --> KC1[(Keycloak)]
flowchart LR
    subgraph G1["Service 1"]
        G_CDMS["CDMS<br/>+ cias-authentication<br/>+ cias-tenancy-client"]
    end
    subgraph G2["Service 2"]
        G_CIAS["cias-runtime"]
    end
    G_CDMS -->|"HTTP: may tenant X<br/>be served?"| G_CIAS
    G_CIAS -->|"HTTP: GET /cias/fetch<br/>(roles, attributes)"| G_CDMS
    G_CDMS --> DB1[("System DB CDMS<br/>+ tenant DBs")]
    G_CIAS --> DB2[("CIAS DB")]
    G_CDMS --> KC2[(Keycloak)]
    G_CIAS --> KC2

All differences in one table

EmbeddedStandalone
Processesonetwo (or more)
What CDMS includesthe CIAS modules directly (with or without starter)only cias-authentication + cias-tenancy-client
How CDMS asks: “May tenant X be served?”method call LocalTenantLookupAdapterHTTP GET /cias/lookup/tenants/{key}, timeout 2 s
Tenant-bound attributesmethod call in cias-userHTTP GET /cias/lookup/users/{id}/attributes?tenantKey=…
How CIAS learns the roles of CDMSas a bean in the same processCIAS calls GET /cias/fetch on CDMS, with a reader realm role of its own (preset declaration-reader)
Database of CIASthe host's system DB; with the starter, one migration history per moduleits own
Token CDMS uses to ask CIASnone neededa service token of its own, fetched by the service itself from Keycloak, never the user token
Token check of the usercias-authentication in the same processcias-authentication in the CDMS process, against Keycloak
CIAS goes downgoes down together with CDMS, there is no “half” stateknown tenants keep running from the cache, unknown ones are rejected
Tenant is suspendedtakes effect after 30 s at most (cache of the tenant gate)takes effect after 30 s at most, from the point of view of each single service
Setting in the generatorcias: EMBEDDED in system.yamlcias: REMOTE – derived when system.yaml says nothing

One request in both operating modes

The same request “list of customers” in both worlds:

GET of the customer list

When: CDMS and CIAS run in the same process, for example the hub backend.

sequenceDiagram
    participant B as Browser/BFF
    participant F as Filter chain (CIAS)
    participant T as Tenant gate (CIAS)
    participant C as CDMS
    participant DB as Tenant DB
    B->>F: POST /crm/customer/query + token
    F->>F: check token, exchange it, resolve tenant
    F->>T: may "kunde-a" be served?
    Note over F,T: method call in the same process
    T-->>F: yes (remembered for 30 s)
    F->>C: RequestContext filled
    C->>DB: SELECT … (only allowed rows)
    DB-->>C: rows
    C-->>B: data + meta

Result: One process, no network call between CDMS and CIAS.

When: CIAS runs as a separate service (cias-runtime).

sequenceDiagram
    participant B as Browser/BFF
    participant F as Filter chain (in CDMS)
    participant R as cias-tenancy-client
    participant S as CIAS service
    participant C as CDMS
    participant DB as Tenant DB
    B->>F: POST /crm/customer/query + token
    F->>F: check token, exchange it, resolve tenant
    F->>R: may "kunde-a" be served?
    R->>S: GET /cias/lookup/tenants/kunde-a<br/>(service account token)
    S-->>R: served: true
    R-->>F: yes (remembered for 30 s)
    F->>C: RequestContext filled
    C->>DB: SELECT … (only allowed rows)
    DB-->>C: rows
    C-->>B: data + meta

Result: One extra HTTP call, but only when the tenant is not in the cache.

What happens when CIAS does not answer?

Only in standalone mode can CIAS go down on its own. Then the memory of the tenant gate decides:

Tenant gate in standalone mode
CIAS answers?Tenant in cache?Result for the request
yes–CIAS decides, the answer is remembered for 30 s
noyesthe last known answer still applies
nono403 tenant-not-served – when in doubt, reject

A 403 from the lookup or a timeout counts as an error, not as a “no”. That is why the cache is an availability buffer, not a speed trick.

Why both modes must behave the same in the subject area

The rule and its consequences
  1. 1
    CIAS
    No CIAS class activates itself. Every module sits behind a switch codamai.cias.<modul>.enabled with no default value
    Otherwise CDMS, which scans all com.codamai classes, would turn on CIAS in every application that only brings the jar along.
  2. 2
    CIAS
    Embedded and standalone run the same code with the same rules and rejections
  3. 3
    CIAS
    Only the adapters are swapped – tenant lookup, attribute lookup and declaration, local or over HTTP, plus the adapter to the identity provider
    Result: A bug that shows up in only one operating mode is, by definition, a bug

Next

Sources in the code and the knowledge base
  • CIAS/cias-parent/docs/cias-overview.md §3
  • CIAS/CLAUDE.md §6, §37, §38
  • CIAS/cias-kernel/docs/adr/adr-022-tenant-lookup-port.md
  • CIAS/cias-tenancy-client/CLAUDE.md
  • hub-backend – CiasEmbeddedConfiguration, pom.xml
Search