---
title: Authentication philosophy
description: The threat model and design principles that underpin every other
  concept in Sudomimus.
editUrl: true
head: []
template: doc
sidebar:
  order: 1
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

Sudomimus treats every protocol boundary as independently exposed: browsers, application servers, native clients, relying parties, and the network between them may each be compromised. A flow should therefore avoid giving any one participant enough material to impersonate every other participant.

These principles apply across Connect, OIDC, and native direct-issue. Some sections use Connect as the concrete example; the protocol-specific mechanics live in the corresponding integration section.

## 1. Redemption proof is scoped to one session

Most auth systems rely on a long-lived shared secret — OAuth's `client_secret`, an API key, a static signing secret in the application's environment. Leak it once, and every past and future exchange is compromised.

Connect avoids using a long-lived shared secret as sufficient proof to redeem every login. Each round-trip mints a **fresh `hiddenKey`** at `/establish`, uses it exactly once at `/redeem`, and then permanently consumes it. Leaking one hidden key compromises that redemption, not every login the application has ever handled.

This is proof-of-possession thinking: short, narrowly-scoped secrets beat long-lived shared ones.

> **What this rejects:** trusting a single long-lived `client_secret` to authenticate every token exchange forever.

## 2. Identity is separate from credentials

A Sudomimus **account** stores who someone is — a stable identity with a name. An **authentication method** stores how they prove it — a passkey, an email address, a Steam identity, an AccessKey credential. The two live in different records, and one account can hold many methods.

Consequences:

- **Account enumeration is harder.** The account record carries no email. An attacker probing whether `alice@example.com` exists has nowhere to query it from.
- **Switching auth methods doesn't touch identity.** A user adding a passkey to their email-OTP account is just a new authentication record. The account stays the same, and so does anything tied to it.
- **There is no password column anywhere.** Sudomimus does not store passwords. It cannot leak passwords because it has none to leak. The supported methods are passkeys, email OTP, social sign-in (Google, GitHub, Discord, Battle.net, X), Steam, and AccessKey credentials, with more being added.

> **What this rejects:** treating email *as* identity, and the legacy of password databases.

## 3. Identity is opaque, and different for every application

Sudomimus never hands your application its internal account identifier. What you receive is a **pairwise identifier** — a stable, opaque `sub` that is unique to *your* application. The same person signing into two different applications presents two unrelated identifiers, and neither can be reversed into the underlying account.

Consequences:

- **No cross-application correlation.** Two applications cannot collude to link "their" users into one real person by comparing identifiers.
- **The identifier is opaque by contract.** It is an exact-match token, not a structured value to parse. Sudomimus can change its internal format without breaking you, precisely because you were never meant to read anything out of it.
- **A leaked token leaks one application's view** of a user — not a platform-wide identity.

> **What this rejects:** a single global user id sprayed across every relying party, turning every integration into a tracking vector.

## 4. Users consent to what each application learns

An access token carries only the identity claims the **user has agreed to share with that specific application**. Email, first name, and last name are each granted or withheld independently, and a grant can be revoked at any time. Inclusion is re-evaluated **live at every issue**, so a revocation takes effect on the next token — not "eventually".

Consequences:

- **A claim you'd like may simply not be there.** Design for its absence. If your application genuinely needs a claim, declare it required — Sudomimus then gates non-interactive issue until the user consents, rather than silently handing you nothing.
- **You store less.** Claims you never receive are claims you never have to protect.

> **What this rejects:** the assumption that an application is entitled to a user's full profile the moment they sign in.

## 5. Verification is cryptographic, not relational

When your application receives an access token, it is a **signed JWT**. To trust it, your application verifies the signature against its own **token-signing public key**, which it fetches once from `POST /info` (the Connect surface) and caches. You do not call Sudomimus on every request to ask "is this user still logged in?".

Consequences:

- **No latency tax** on every authenticated request — verification is local.
- **No availability dependency** between your service and Sudomimus once the user is signed in.
- **Tokens are deliberately short-lived** (access tokens default to a few hours, not days). When they expire, one HTTPS call against `/refresh` gets a new one — far cheaper than re-authenticating the user.

OIDC ID tokens are a separate case: relying parties verify them against the JWKS at `oidc.sudomimus.com/.well-known/jwks.json`. See [Tokens and verification](/en-us/concepts/tokens-and-verification/) for the full picture.

> **What this rejects:** the stateful session-on-IdP model that turns every authenticated request into a remote lookup.

## 6. Access is allow-listed and default-deny

Who may complete an authentication, by which method, and how the result is returned are all governed by explicit allow-lists. An application that has configured nothing authenticates **nobody**. The safe state is the default: access is something you deliberately open up, never something you have to remember to lock down.

> **What this rejects:** systems that are wide open until an administrator remembers to restrict them.

## 7. Failure is scoped, not amplified

A common anti-pattern is the **account lockout**: too many wrong attempts and the account is frozen for an hour. It makes brute force harder, but it also gives anyone who knows your email a free denial-of-service vector.

Sudomimus does it differently. Each authentication session carries its own *life* counter. Wrong attempts decrement that session's life — not the account's. When a session runs out of life, that session dies; the user simply starts another one. The account itself is never locked.

> **What this rejects:** punishing the legitimate user for the attacker's behaviour.

## 8. Three keys, three vantage points

To forge a successful `/redeem` against Sudomimus, an attacker must simultaneously hold:

- A secret that lives only on the application server (the **hidden key**)
- A reference that was only ever sent to one specific browser (the **exposure key**)
- A proof that Sudomimus only mints after a real challenge succeeds (the **confirmation key**)

No single point of failure produces all three. A leaked URL does not compromise the server's secret. A compromised server does not compromise other users' sessions. A phished user does not compromise the server.

The mechanics are in [the three-key model](/en-us/connect/three-key-model/). The principle is general: split a proof three ways across three trust domains.

> **What this rejects:** monolithic session tokens whose theft is full compromise.

## 9. Trust boundaries are enforced, not documented

Sudomimus has exactly five public surfaces — `connect-api.sudomimus.com`, `via.sudomimus.com`, `device-api.sudomimus.com`, `native-api.sudomimus.com`, `oidc.sudomimus.com`. Everything an integration can reach, it reaches through one of these; anything else is internal, and *internal* here means unreachable from outside the platform — enforced at the platform edge, not asserted in a document and left one misconfiguration away from exposure.

The practical consequence: there are a small number of well-defined paths through which an authentication can be completed, and integrations cannot bypass them.

> **What this rejects:** soft conventions like "this is an internal API, please don't call it."

## What this means for you

When you integrate with Sudomimus, you inherit these properties for free:

- You never see a password, so you have nothing to store securely.
- You receive an opaque, per-application identifier — you cannot accidentally become a cross-site tracking vector, because you were never given a global id to leak.
- You only ever hold the identity claims a user agreed to share with you.
- Your application verifies tokens offline; Sudomimus availability doesn't gate access to your own backend.
- A leak of any single secret in your application is bounded to one session.
- You don't need to build account lockout logic.
- You don't need to write account-enumeration defences.

Next, [choose an integration path](/en-us/getting-started/choose-integration/) or inspect the concrete [Connect flow](/en-us/connect/flow/).