Layer 3 — Return rules
Layer 3 controls how an authentication result reaches the application. It is checked twice: once at /establish (against each return method declared on the request) and again at runtime when the chosen method actually runs (for example on /status-poll, or inside the OIDC /token exchange).
Supported return methods
Section titled “Supported return methods”| Method | Payload (per inquiry) | Used for |
|---|---|---|
CALLBACK | { "callbackUrl": "https://..." } | Web applications — the browser is redirected to a URL on the application after authentication. |
STATUS_POLL | {} | Native clients — the client polls connect POST /status-poll and is told when the inquiry is realized. |
REVEAL | {} | Developer / CLI / manual integration — the access and/or refresh tokens are shown directly on via.sudomimus.com after login (masked, with a “Reveal” button) so the user can copy them out by hand. No application sits on the other end. |
DIRECT_ISSUE | {} | Opts the application in to one-shot native-api issuance — Steam ticket (POST /direct-issue/steam-ticket) or AccessKey (POST /direct-issue/access-key). Tokens are minted in the same request that authenticates; no /establish or /redeem is involved. |
OIDC | (not declared per inquiry) | Enables this application to be used as an OIDC relying party via oidc.sudomimus.com. Required for the OIDC authorization_code + PKCE flow. |
CALLBACK — application rule shape
Section titled “CALLBACK — application rule shape”A CALLBACK rule on the application carries the allowed hostnames for the callback URL — not the URL itself. The actual URL is supplied per-inquiry on /establish; the rule decides whether that URL’s hostname is acceptable.
{ "returnMethod": "CALLBACK", "payload": { "allowedCallbackDomains": ["client.example.com", "admin.example.com"] }, "accessTokenTtlSeconds": null, "refreshTokenTtlSeconds": null}Hostname comparison is exact, case-insensitive — client.example.com does not implicitly cover sub.client.example.com. To allow both, list both.
STATUS_POLL — application rule shape
Section titled “STATUS_POLL — application rule shape”STATUS_POLL rules have no payload — having the rule on the application is the whole configuration.
{ "returnMethod": "STATUS_POLL", "payload": {}, "accessTokenTtlSeconds": null, "refreshTokenTtlSeconds": null}REVEAL — application rule shape
Section titled “REVEAL — application rule shape”REVEAL rules configure which tokens are shown to the user after a successful login. At least one of includeAccessToken and includeRefreshToken must be true.
{ "returnMethod": "REVEAL", "payload": { "includeAccessToken": true, "includeRefreshToken": true }, "accessTokenTtlSeconds": null, "refreshTokenTtlSeconds": null}When an inquiry declares REVEAL, Sudomimus signs the tokens at realize time and returns them inline; the inquiry is marked redeemed immediately, so any subsequent /redeem call for the same login fails with InquiryAlreadyRedeemed. Multiple matching REVEAL rules are combined with OR semantics — if any matching rule allows the access token, it is included; same for the refresh token.
Combining REVEAL with other methods
Section titled “Combining REVEAL with other methods”REVEAL takes precedence on the via.sudomimus.com page: it suppresses the automatic CALLBACK redirect so the user can copy the tokens first. The user then sees a “Continue to app” button if a CALLBACK was also declared. STATUS_POLL still signals realized to a polling client, but the subsequent /redeem will fail because REVEAL has already redeemed the inquiry.
DIRECT_ISSUE — application rule shape
Section titled “DIRECT_ISSUE — application rule shape”DIRECT_ISSUE rules have no payload — the rule’s presence is the entire configuration. Add this rule to opt an application in to the native-api direct-issue endpoints (Steam ticket and AccessKey).
{ "returnMethod": "DIRECT_ISSUE", "payload": {}, "accessTokenTtlSeconds": null, "refreshTokenTtlSeconds": null}DIRECT_ISSUE does not appear in /establish returnMethods declarations — those endpoints have no /establish step. Layer 3 is still checked at runtime inside the native-api handlers.
OIDC — application rule shape
Section titled “OIDC — application rule shape”OIDC rules opt the application in to being used as an OpenID Connect relying party via oidc.sudomimus.com. The payload carries the standard OIDC client configuration:
{ "returnMethod": "OIDC", "payload": { "redirectUris": ["https://app.example.com/oidc/callback"], "postLogoutRedirectUris": ["https://app.example.com/"], "allowedScopes": ["openid", "email", "profile", "offline_access"], "tokenEndpointAuthMethod": "private_key_jwt" }, "accessTokenTtlSeconds": null, "refreshTokenTtlSeconds": null}redirectUris— full-URI exact match. Theredirect_uriparameter the RP sends to/authorizemust equal one of these strings byte-for-byte. No prefix or wildcard matching.postLogoutRedirectUris— full-URI exact match, used by/end-session.allowedScopes— the set of OIDC scopes this client is permitted to request.openidis always required;email,profile, andoffline_accessare supported. Requesting a scope outside this list fails at/authorize.tokenEndpointAuthMethod— one of"private_key_jwt"(confidential client; signs a JWT assertion to authenticate at/token),"client_secret_basic"(confidential client; presents a shared secret in the HTTPAuthorization: Basicheader),"client_secret_post"(confidential client; sends a shared secret in the/tokenform body), or"none"(public client; PKCE is required for these).
OIDC rules are not declared per-inquiry on /establish — the OIDC flow has its own /authorize endpoint instead.
End-to-end usage and library setup is in OIDC relying parties.
Declaring on /establish
Section titled “Declaring on /establish”The returnMethods field on /establish plays two roles at once: it declares which methods will be used for this inquiry and it carries the concrete callbackUrl (which the application’s rules cannot know in advance).
{ "applicationAnchor": "my-app", "returnMethods": [ { "type": "CALLBACK", "payload": { "callbackUrl": "https://client.example.com/auth/return" } }, { "type": "STATUS_POLL", "payload": {} }, { "type": "REVEAL", "payload": {} } ]}DIRECT_ISSUE and OIDC are not declared on /establish — those flows do not pass through it.
- Field absent → no Layer 3 narrowing; the application’s rules still apply at runtime.
- Field present and empty array → rejected.
- Field present and non-empty → every entry is validated against the application’s Layer 3 rules at
/establishtime. ForCALLBACK, the URL’s hostname must match an entry in some Layer 3CALLBACKrule’sallowedCallbackDomains. ForSTATUS_POLLandREVEAL, a Layer 3 rule of the same method must exist on the application.
Worked example
Section titled “Worked example”The application has one Layer 3 rule: CALLBACK with allowedCallbackDomains: ["client.example.com"].
Inquiry callbackUrl | Result |
|---|---|
https://client.example.com/return | accepted |
https://Client.Example.Com/return | accepted (case-insensitive) |
https://sub.client.example.com/return | rejected (no implicit subdomain match) |
https://attacker.com/?redirect=client.example.com | rejected (hostname is attacker.com) |
For STATUS_POLL, the runtime check on /status-poll re-verifies both that the application still has a STATUS_POLL rule and that the inquiry’s per-inquiry narrowing (if any) still allows it.
Why hostname-only (for CALLBACK)
Section titled “Why hostname-only (for CALLBACK)”The check matches only the hostname, not the path or query string. Sudomimus does not own the application’s URL structure and would create a maintenance burden by requiring exact-path allowlists. Application owners are expected to keep their callback handlers safe at the routing level — Sudomimus restricts the origin the browser is sent to.
(OIDC redirectUris are a different model — they require full-URI exact match because the OIDC standard demands it and because most OIDC libraries already produce a single fixed redirect URI per client.)