Skip to content

OAuth APIs (Resource Servers)

An OAuth API in Modgud is the registration of a resource server — an API that wants to validate access tokens issued by Modgud and use them to authorise requests.

OAuth API vs OAuth Client

  • OAuth Client = the app that performs the user login and gets tokens
  • OAuth API = the API that validates tokens and authorises requests against them

An app can be both (e.g. a BFF pattern: user-login as a client, its own API as an API).

OAuth APIs list

When do I need an OAuth API registration?

For most cases — a SaaS app that validates Modgud tokens — yes, you register an OAuth API for it. The registration is what lets Modgud emit a tailored resource_access block for this RS on /connect/userinfo. Specifically, it's required when:

  • You want per-Audience permission narrowing in resource_access blocks. The RS declares its PermissionIds subset of the App's catalog, and the IdP narrows each user's emission to that subset.
  • The API wants to authenticate against the OAuth server itself (e.g. for token introspection)
  • You want multi-secret support (several parallel valid secrets, e.g. for seamless rotation)
  • The API needs explicit scope lists for discovery

Relationship to Applications

Every OAuth API belongs to exactly one Application. A microservice architecture under one app — e.g. acme-api, acme-search, acme-files all linked to the App acme — works because permissions stay app-centric: each microservice gets its own PermissionIds subset of the same App catalog, and the IdP narrows its resource_access[acme] emission accordingly.

Creating an API

Administration → OAuth → APIsCreate.

Required fields

  • Name — technical identifier (e.g. acme-api). Used in aud claims when the token is issued.
  • Display Name — UI label
  • Application — which App does this RS belong to? Required for per-Audience subset narrowing.
  • Description — optional

PermissionIds

The subset of the linked App's catalog this RS gates on. Used by the IdP to narrow the resource_access block in UserInfo for this audience — sibling RSs under the same App don't see each other's permissions in the user's claims.

Default at creation: full catalog. Tighten to a strict subset for microservices that only need a slice.

Scopes

A list of scope names this API understands. Any token whose scope claim contains one of these is considered "for this API". Used for OIDC discovery and resource indication.

One-click implicit scope

In the API detail modal there is a Create implicit scope button when the API has no scope with the same name yet. Clicking it creates a real OAuthScope row with:

  • Name = API name
  • Resources = [<api-name>] (so the audience matches the API)
  • Enabled = true, ShowInDiscoveryDocument = false (private by default, see below)
  • Linked to the same App as the API

This is the fast path for the common 1:1 case: an API and a scope that always go together. After creation the button disappears (re-check via API list reload). The implicit scope is otherwise a normal scope row — editable, deletable, can be requested by clients via scope=<api-name>.

When to keep things separate

Two situations warrant a manually-created additional scope on top of the implicit one:

  • Granularity<api>.read / .write / .admin against the same audience. Differentiates capabilities via scp, not aud.
  • Multi-RS scope — one scope name pointing to multiple APIs (scope=adminaud: [policy-api, audit-api]). Edge case but valid.

User claims

Optional list of claim types this API expects in tokens. Used by some IdP-side filtering mechanisms; for most setups, leave empty.

How a resource server authenticates against Modgud

An OAuth API has no credential surface of its own. When the resource server needs to call Modgud directly (e.g. token introspection), it does so via OAuth using a confidential OAuth Client linked to a Service Account: the client requests an access token via Client-Credentials and uses it as a bearer like any other token. There is no per-API shared secret to rotate.

Editing

Most fields can be edited live; Name is immutable after creation. Changing the linked Application is allowed but be careful — the RS's scope-resolution and the per-Audience resource_access shape immediately switch to the new app context.

Deleting

List → right-click → Delete. Soft-deleted; the OAuth API is no longer usable but the aggregate stream is retained for audit.

Common patterns

One app, one resource server

Default for most SaaS apps: create one OAuth API named after the app's slug, link it to the App, and pick the catalog subset it gates on.

One app, multiple resource servers (microservices)

Each microservice gets its own OAuth API entry with its own narrower PermissionIds subset of the App's catalog. All link to the same App. Per-Audience narrowing in UserInfo means a token used against microservice A only carries A's permission subset, not B's — even when both are under the same App.

Multi-tenant API

If the same API logic serves multiple realms, each realm gets its own OAuth API entry. Modgud's tenancy already enforces realm separation at the database level, so cross-realm token leakage is impossible.

Tips

Audit trail

RS-Auth-protected endpoint calls log the calling RS's name. Useful when several microservices share one App and you want to know which specific RS made a given request.

Two distinct identities

A user bearer token identifies the user; the RS-as-OAuth-client identity (a Client-Credentials access token minted via a Service Account) identifies the RS itself. They sit on independent authentication axes — both can be relevant on the same request.

Released under the Apache-2.0 License.