The three-layer rules model
Every application on Sudomimus is gated by three independent layers of rules. Each layer answers a different question, lives in its own configuration, and is evaluated at a different point in the authentication flow. None of them have implicit defaults: a layer with zero rules allows nothing.
The three layers
Section titled “The three layers”| Layer | Question it answers | Checked when |
|---|---|---|
| Layer 1 — Authentication | Which authentication methods may be used? | A method is offered to the user, and again at every attempt. |
| Layer 2 — Realize | Which identities may complete authentication? | Post-authentication, before the inquiry is marked realized. |
| Layer 3 — Return | How the result is delivered back to the application? | At /establish (against declared return methods) and at runtime (e.g. /status-poll). |
Splitting the decision this way means each axis can change independently — opening a new authentication method does not silently widen who can sign in, and tightening the allowed callers does not require touching authentication configuration.
Allowlist with default-deny
Section titled “Allowlist with default-deny”Every layer is allowlist-only. A new application starts with zero rules in all three layers and cannot be used until rules are explicitly created. There is no implicit “allow everything” mode, and removing the last rule from a layer disables the application — it does not fall back to a default.
This is deliberate: an authentication system that defaults to allow tends to leak access whenever the surrounding configuration is misunderstood. Defaulting to deny means a misconfiguration produces a visible failure rather than a silent breach.
Per-inquiry narrowing
Section titled “Per-inquiry narrowing”Application-level rules describe what the application as a whole is willing to allow. A single login session is often more specific — a sensitive admin flow may want passkey only; a tenant-scoped flow may want a single email allowlist. The /establish request therefore accepts three optional narrowing fields:
Field on /establish | Narrows |
|---|---|
authenticationConstraints | Layer 1 |
realizeConstraints | Layer 2 |
returnMethods | Layer 3 |
Each field’s shape mirrors the corresponding rule shape, so the same vocabulary is used in both places.
- Field absent — no narrowing for that layer; the application’s rules alone decide.
- Field present and empty array — rejected. An empty narrowing would mean “allow nothing”, which is what removing the rules from the application already expresses.
- Field present and non-empty — every entry is structurally validated and stored on the inquiry. At evaluation time it is AND-combined with the application’s rules.
OR within, AND across
Section titled “OR within, AND across”When multiple records could apply at the same evaluation point, the combiner is:
- OR within a single layer and a single source — multiple matching application rules in Layer 1, for example, all stack: any match passes.
- AND across layers, and AND across (application rules, inquiry constraints) — Layer 1, Layer 2, and Layer 3 must each pass, and within each layer both the application rules and the (optional) inquiry constraints must allow it.
The result is that narrowing on an inquiry can only further restrict — it can never grant something the application itself did not allow.
Token TTLs
Section titled “Token TTLs”Every rule and every per-inquiry constraint can optionally carry accessTokenTtlSeconds and refreshTokenTtlSeconds. The Connect API computes the final TTLs by collecting all matching values across every layer and source and taking the minimum — the strictest setting wins.
Defaults are 3 hours for access and 30 days for refresh. The refresh TTL is always raised to be at least the access TTL. The full bounds (60 seconds – 7 days for access; 1 day – 365 days for refresh) are in Tokens and verification.
Where to go next
Section titled “Where to go next”Each layer has its own page with the per-layer schema, glob/match semantics, and a worked example: