Skip to content

Glossary

Terms in modgud and their counterparts in other identity systems.

Core terms

Realm

An isolated identity boundary. Each realm has its own PostgreSQL database (<master-db>_<slug>), its own users, roles, OAuth clients, and login providers.

Mapping to other systems:

modgudKeycloakAuth0Azure AD
RealmRealmTenantTenant (Directory)

The system realm is the first realm, created automatically on first boot. It starts as the Control-Plane realm — flagged IsControlPlane = true — meaning only its users may create further realms. Exactly one realm per deployment is the Control Plane.

The realm boundary is the domain (Host header), not the URL path. Realm acme lives under acme.example.com, the system realm under system.example.com or localhost.

Application

A soft facet within a realm — not an isolation boundary. An Application owns a permission catalog (its <resource>:<action> entries) and, since ADR-0011, an optional login experience: its own subdomain, branding, email branding, and sparse per-app overrides of the realm's self-registration / native-grant / DCR / CIMD policy. All apps in a realm share the realm's user pool — one account, one sub, no shadow users.

Tenant vs. Application: the realm (tenant) is the hard boundary (own DB, signing keys, OIDC issuer, user pool, apex); an Application is a refinement inside it. Promote an App to its own realm only when you need independent key rotation, breach containment, or data isolation.

In code: Modgud.Authorization.Apps.App (the catalog discriminator) plus the tenant-scoped ApplicationSettings document (the override doc, keyed by App.Id).

SelfRegPosture

How an Application triggers a passwordless self-registration: Off (none), JitOnOtp (sign-in-or-sign-up on an unknown email — the consumer default), ExplicitEndpoint (a deliberate separate registration step, so sign-in stays strict for known users only), or InviteCode (invite-only — an unknown email can only self-register with a valid, unused invite code; everyone else gets the same anti-enumeration response as Off). Lives in an App's self-registration settings.

User

A human or service account inside a realm. Users belong to exactly one realm. Identical usernames in different realms are different accounts.

In code: Modgud.Authentication.Domain.ApplicationUser (ASP.NET Core Identity user).

Group

An organisational unit. Groups have members (users or other groups) and carry PermissionRole references. Groups exist in two modes:

  • Manual — admin maintains the member list
  • Auto — a membership script determines members dynamically

See Auto membership.

PermissionRole

A named bundle of permissions. Binds to one App (or to the realm when IsRealmAdmin = true) and references a list of the App catalog's PermissionIds:

Name:          "User Manager"
AppId:         <modgud app id>
PermissionIds: [user:read, user:write]

Permission

A two-segment string <resource>:<action> inside an App's catalog — the App context is implicit from the catalog container. Examples: user:read (in the modgud app), invoice:write (in a billing app), realm:admin (realm-constant bypass). Permissions flow exclusively through groups:

User → Group → Role → Permission

Two bypass tiers: <resource>:admin (resource-wide within the calling app) and realm:admin (realm-wide emergency exit). See Permissions & gating for the full evaluator + UserInfo-emission story.

Session

A server-side record (UserSession Marten document) of an active login. Tracks IP, browser, OS, device type, LastActiveAt, ExpiresAt. Users can revoke their own sessions; admins can force-logout users. The browser, OS, and device type are detected from the request's user agent.


OAuth / OIDC terms

Client (OAuth application)

An external application that requests user logins or API access. Created per realm — the same client_id in realm A and realm B are different clients.

Configurable per client:

  • Client ID — public identifier (e.g. my-app)
  • Client Secret — private key (for confidential clients)
  • Redirect URIs — allowed callback URLs
  • Grant Types — which flows are allowed
  • Access Token Type — Reference (default) or JWT

Scope

A permission boundary that a client can request. Scopes appear in the token; resource servers decide based on the scopes whether the request is OK.

Default scopes (set per realm at realm provisioning):

  • openid — required for OIDC, returns the user ID
  • profile — first name, last name
  • email — email address
  • roles — role memberships
  • offline_access — enables refresh tokens

API (resource)

A protected backend API. Has an identifier (audience claim in the token) and a list of scopes it supports. In code: OAuthApiAggregate.

Grant Type

Grant TypeUse case
Authorization Code + PKCEWeb apps, SPAs, mobile apps
Client CredentialsMachine-to-machine, background services
Refresh TokenRenew expired access tokens

No Implicit, no ROPC

Modgud supports neither Implicit Flow nor Resource Owner Password Credentials (ROPC). Both are considered insecure and are deprecated in OAuth 2.1.

Token types

TypeWhat it is
Access TokenAccess to APIs. Reference (opaque, via introspection) or JWT (self-contained)
Identity TokenWho signed in — consumed by the client
Refresh TokenGet a new access token without a fresh login

Access token format

Configurable per client:

FormatHow it worksBest for
Reference (default)Opaque string. APIs validate via the introspection endpoint.SPAs, mobile, public clients — instant revocation.
JWTSelf-contained, signed token. APIs verify locally.Trusted backend services — no introspection roundtrip.

Which one when?

Reference tokens are the safe default. Revoke a reference token and it is dead immediately. JWTs cannot be revoked — they are valid until they expire. Use JWT only for trusted services where the introspection roundtrip gets in the way.


Login providers

An authentication method that users can use. A single LoginProvider aggregate per entry, with a Type discriminator. Configurable per realm.

TypeStatusDescription
InternalWired upBuilt-in username/password. Auto-seeded once per realm, marked IsBuiltIn=true, not editable from the admin UI.
OidcWired upExternal OIDC IdPs (Entra ID, Google, Auth0, ...). Authority + client ID + secret + UserUpdateScript.
SamlWired upExternal SAML 2.0 IdPs. See SAML federation.
Ldap / KerberosReservedEnum values exist; create endpoint rejects with LoginProvider.TypeNotSupported. The shape ships now so the FE doesn't have to add a "not supported yet" UI per type later.

Configured Oidc providers automatically show "Login with {Provider}" buttons in the login UI. Internal never produces an SSO button — it backs the local username/password form.


Terms in code

Term in codeTerm in docs/UIWhere
TenantIdRealm slugMarten/Wolverine, infrastructure layer
PrincipalUser or group or service accountAuthorization slice (polymorphic)
PersonUser read model in the authorization sliceA subclass of Principal
AggregateEvent-sourced entityDomain layer
*StateInline projection for sync consistencyInfrastructure layer
*ListReadModel / *DetailsReadModelAsync projection for read optimizationInfrastructure layer
LoginProviderLogin provider configuration (Internal / Oidc / ...)Authentication slice

"Realm" vs. "Tenant"

User-facing it is Realm everywhere. The code uses Tenant in the infrastructure layer (TenantId, ITenantSessionFactory, MasterTableTenancy), because that is what Marten and Wolverine call it. Same thing, two names.

Released under the Apache-2.0 License.