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
Identity across the Splenta 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
ICE signs. Each product 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 exactly what the permissions allow.
ComputePlatform identity
One issuer. Consistent enforcement.
ICE gives every Splenta product, user, service and agent one shared identity and authorization model, deployed within each customer's environment.
Under the hood
Central signing. Product-level enforcement.
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 - warehousing
- - wms:stock:write
FMS - finance
- - fms:gl:write
HMS - healthcare
- - 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 keep the boundary clear: authorization_code + PKCE for human workbenches, and client_credentials for agents and services. The shared client catalog remains the source of truth.
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
Host the identity layer your apps share.
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.