ICE - identity for the whole product family
One login. One scope catalog.
One root of trust.
ICE is the single sign-in and authorization server for the whole Splenta family. Every product validates its tokens; nobody re-implements identity, tenancy or login.
- issuerice.<customer>who signed it
- tenantmercy-generalacting in
- scopehms:patient:read, ice:user:readwhat it may do
- audiencehms-apiwho it is for
One RS256 token. Every product verifies it against ICE's public key - no shared secret, no callback home.

What ICE is
One identity plane for the whole family.
Not a bolt-on login for one app - the shared identity and access layer every product is built on. One short line each, no jargon.
Single sign-in
One login, one issuer
Sign in once through ICE. Every other product (SCM, Arin, RMS, WMS, FMS, HMS) trusts the same token - none ships its own login form.
One vocabulary
One scope catalog
129 permissions, defined once as code. Every product reads the same vocabulary; none invents its own.
Tenancy
Multi-tenant IAM
One global identity across many tenants. Switch tenant and the token is re-minted - so no product builds tenancy for itself.
Access model
Roles, permissions, groups
App-roles bundle permissions; groups carry roles to their members. Business roles stay in the product that owns them.
Policy
ABAC policy
A closed, fail-closed condition policy grants or revokes access at sign-in time. Revoke always beats grant.
Migration
Gradual enforcement
Move each product from off to report to enforce on its own schedule - never one irreversible switch for everyone.
The trust chain
One issuer signs. Every product just verifies.
- A person signs in once - no product ships its own login form.
- Products cache the public key, so a brief ICE blip never stops verification.
- No shared secret ever leaves ICE, and no token is phoned home to check.
InfrastructureEnforcement modes
Migrate at your own pace.
- off - nothing is checked, before a tenant is modelled.
- report - the default: ICE logs what it would deny, but issues the scopes anyway.
- enforce - scopes are narrowed to what the permissions allow. HMS runs here today; the rest stay in report.
ComputeWhere it fits
Not a broader IdP. A sharper one.
ICE is purpose-built platform identity for the Splenta family, self-hosted per customer - not a general-purpose CIAM you buy to secure your own app. The hosted providers are genuinely good at breadth; ICE trades that for one deployment shape and a shared, code-verified catalog.
The hosted and open providers keep their real strengths in breadth, MFA, SSO and federation - none of which ICE offers today. ICE trades all of that for a single deployment shape, a code-verified shared scope catalog and a decide-once, enforce-everywhere claim contract. It is pre-revenue with no shared production deploy, which we say plainly. If you need a general CIAM for your own product, one of the others is the better answer.
Under the hood
One issuer, one signature, many enforcers.
The story above is the plain version. For evaluators, here is the mechanism - ICE is built on Spring Authorization Server (Java 17, PostgreSQL), and every other product is a pure resource server that holds no signing key.
The signed claim contract
Access decisions travel inside the token as claims. ICE mints an RS256 JWT; the audience is derived from the scope prefixes, never configured per client. The public JWKS on the right is the only thing a product needs to verify it.
Verify, then authorize
Resource servers never hold a secret from ICE and never call back to check a token. They verify a signature against a published key, confirm the token is for them, then decide on their own what its scopes allow.
sign in
A person signs in
authorization_code + PKCE, once
PDP - decides
ICE mints a token
RS256 JWT of resolved claims
public key
Product reads the JWKS
Cached from /oauth2/jwks
PEP - enforces
Validate + enforce scopes
Per request, holds no signing key
One scope catalog - 129 scopes
Every scope in the family is defined once, as code, in a single catalog ICE owns. It exists as both a document and a source file, held in strict parity by a test - so what a product reads is exactly what ICE issues. Authority reads the same everywhere: domain:resource:action, and the audience comes from the prefix.
ICE - identity + IAM
- - ice:user:read
- - ice:tenant:write
- - ice:policy:write
SCM - procurement
- - scm:po:approve
Arin - agent layer
- - arin:agent-action:write
RMS - retail
- - rms:order:write
WMS - warehouse
- - wms:stock:write
FMS - finance
- - fms:gl:write
HMS - hospital
- - hms:patient:read
129 total
Across all seven domains. The names above are representative, not the whole set - the catalog is the source of truth, parity-gated in CI.
The seeded client roster
Two grant types, by design, and no others - authorization_code + PKCE for human workbenches, client_credentials for agents and services. The clients below are real and seeded. A Clients admin UI is designed but not built yet.
Human clients
authorization_code + PKCE - public - 15-min access / 7-day refresh
- ice-workbench
- scm-workbench
- arin-workbench
- rms-merchant
- rms-admin
- wms-workbench
- hms-workbench
Machine clients
client_credentials - agent_id-tagged - identity-neutral claims
- arin-scm-client
- scm-service
- wms-service
- arin-rms-client
- arin-wms-client
- arin-hms-client
- ice-mcp-dev
Audience routing, live
Mint one token, then watch its audience recompute from the scope prefixes as independent resource servers accept or ignore it. One signature, checked against the published JWKS - each server honours only the scopes prefixed with its own domain.
Minted access token
{ alg: "RS256", kid: "ice-rs256" iss: "https://ice.splenta.internal" sub: "arin-scm-client" principal_type: "CLIENT" aud: ["arin-api", "scm-api"] }
signed RS256 - verifiable against /oauth2/jwks
Verified independently by
- SCM aud=scm-apiaccepts
- Arin aud=arin-apiaccepts
- RMS aud=rms-apino authority
- HMS aud=hms-apino authority
One signature, checked against the published JWKS - no shared secrets ever leave ICE. A token can target several products at once; each server honors only the scopes prefixed with its own domain.
Family-internal platform identity
One issuer for the family. Yours to host.
ICE is the identity backbone the rest of the Splenta family is built on - not a product you buy to secure your own app. If you are evaluating the family, or want to walk the trust chain and the claim contract in detail, talk to us and we will show you the architecture.