Authorize applications with a flespi realm OAuth server

Configure a realm OAuth server so applications can act on behalf of realm users.

Configure a realm as an OAuth 2.0 authorization server so applications can act on behalf of realm users without asking them to create or share flespi tokens.

Realm OAuth is different from adding an external identity provider to a realm. An external identity provider lets flespi authenticate a user through another service. Realm OAuth makes flespi the authorization server for applications that need access to flespi. The two features can work together: a user may authenticate to realm OAuth with either realm credentials or an identity provider configured for the realm.


Supported OAuth profile

Realm OAuth supports public clients with the following profile:

Capability Supported value
Authorization flow OAuth 2.0 Authorization Code grant
Client identification Client ID Metadata Document (CIMD) URL
Client authentication None; clients have no secret
PKCE Required, S256 only
Response type code
Grant types authorization_code, refresh_token
Scope default
Access token Opaque Bearer token with a 1-hour deadline; effective usability may be shorter
Refresh token Single-use rotating token with a 14-day lifetime, bound to the source realm user token

The default scope does not define a separate permission set. The realm user's token ACL, token home, origin restrictions, and other token parameters determine what the application can do.

Prerequisites

Before enabling realm OAuth:

  1. Create and configure a realm.
  2. Create at least one enabled realm user or configure an identity provider that can authenticate or register realm users.
  3. Configure the realm role or user token parameters with the minimum access the application needs.
  4. Obtain the OAuth client's public HTTPS CIMD URL.

OAuth is disabled by default for new realms. A realm owner controls which clients may start and complete OAuth grants.

Configure the OAuth client

Client ID Metadata Document

Realm OAuth does not use a conventional client-registration endpoint. The OAuth client_id is a public HTTPS URL that serves a JSON Client ID Metadata Document. The exact same URL must appear in the realm's oauth_server.allowed_clients list.

A web client can publish a document like this:

{
  "client_id": "https://client.example/oauth/client-metadata.json",
  "client_name": "Example operations application",
  "application_type": "web",
  "redirect_uris": [
    "https://client.example/oauth/callback"
  ],
  "response_types": ["code"],
  "grant_types": ["authorization_code", "refresh_token"]
}

The document must satisfy these rules:

  • client_id is required and must exactly match the URL from which the document is retrieved.
  • redirect_uris is required and must contain at least one URI.
  • client_name is optional. If present, flespi displays it on the consent dialog.
  • application_type may be web or native and defaults to web.
  • If response_types is present, it must include code.
  • If grant_types is present, it must include authorization_code.
  • Additional properties are accepted and ignored by realm OAuth.

The CIMD endpoint must return HTTP 200 without redirecting. The response body may not exceed 64 KiB. Valid client metadata is cached for up to one hour, so changes to the document may not take effect immediately.

Redirect URIs

For a web client, every redirect URI must use HTTPS and the authorization request must match one of the registered values exactly.

A native client may also register HTTP loopback callbacks:

{
  "client_id": "https://client.example/oauth/native-client.json",
  "client_name": "Example desktop application",
  "application_type": "native",
  "redirect_uris": [
    "http://127.0.0.1/oauth/callback",
    "http://[::1]/oauth/callback"
  ]
}

For these native loopback callbacks, the client may select a runtime port. Only the port may differ from the registered URI:

Registered: http://127.0.0.1/oauth/callback
Requested:  http://127.0.0.1:49152/oauth/callback

The token request must send the exact redirect URI used by the authorization request, including the runtime port. Web clients must register HTTPS redirect URIs. Plain HTTP is supported only for native applications using 127.0.0.1 or [::1] loopback callbacks; localhost and non-loopback addresses are not accepted.

Enable realm OAuth

Enable the OAuth server in the realm configuration and allow each client by its exact CIMD URL. A realm can allow up to 16 unique clients.

{
  "oauth_server": {
    "enabled": true,
    "allowed_clients": [
      "https://client.example/oauth/client-metadata.json"
    ]
  }
}

URL matching is exact and case-sensitive. Different paths, query strings, trailing slashes, or other URL variants identify different clients. Client URLs must use HTTPS and may not contain fragments.

You can configure the same fields through the Platform realms API. An empty allowed_clients array denies all OAuth clients. A client is checked against this list before flespi retrieves its metadata, and again before authorization-code and refresh-token exchanges.

Connect an OAuth client

Replace <realm-public-id> with the public ID shown in the realm configuration. Configure a compatible OAuth client with these values:

Client setting Value
Issuer / authorization server identifier https://flespi.io/realm/<realm-public-id>/oauth
Discovery metadata https://flespi.io/.well-known/oauth-authorization-server/realm/<realm-public-id>/oauth
Client ID Exact CIMD URL added to allowed_clients
Client secret None
Scope default
Grant Authorization Code
PKCE Required, S256
Authorization endpoint https://flespi.io/realm/<realm-public-id>/oauth/authorize
Token endpoint https://flespi.io/realm/<realm-public-id>/oauth/token

Prefer authorization-server discovery when the client accepts an issuer or metadata URL. Enter the authorization and token endpoints explicitly only when the client does not support discovery.

Use the CIMD URL as the client ID; flespi does not generate another identifier or client secret. The OAuth client owns its callback URI and publishes it in the CIMD. The realm owner does not copy or store callback URIs in realm configuration.

A client is incompatible if it requires a client secret, dynamic client registration, a non-URL client ID, or a PKCE method other than S256.

Tokens and permissions

The opaque Bearer represents the realm user's underlying flespi token. Its ACL, account hierarchy, origin restrictions, expiration, and other token parameters remain effective. Configure these through the realm role or user as described in flespi token - access key to the flespi platform.

The Bearer has a one-hour deadline, but may stop working earlier if its underlying flespi token expires or is invalidated.

A refresh token is bound to the exact source flespi token, OAuth client, and realm user. It can be exchanged only while the source token remains valid and is still the realm user's current token. Deleting, logging out, invalidating, or replacing the source token invalidates its refresh tokens; a refresh exchange never creates a replacement flespi token.

Refresh tokens have a 14-day lifetime. Each successful exchange consumes the refresh token and returns a new Bearer and a new refresh token with another 14-day lifetime.

Refresh also requires the realm, realm OAuth server, client admission, and realm user to remain enabled. Refreshing does not revoke access tokens issued earlier.

Security and audit

Use least-privilege permissions

OAuth does not expand or narrow the realm user's permissions. Configure the realm role or individual user with only the API access and origins required by the client.

Allow only trusted CIMD URLs

The CIMD URL is the public identity of a client; there is no client secret. Allow only HTTPS URLs controlled by the intended application publisher. Confirm the document's redirect URIs before adding it to a realm.

Client metadata retrieval does not follow redirects and applies flespi network-address restrictions. Exact allowlisting happens before the retrieval request, which prevents arbitrary unlisted URLs from being fetched.

Monitor realm events

Use the realm's Logs tab to audit client admission:

Event code Meaning
1202 OAuth client was denied access to the realm
1203 OAuth client was granted access to a realm user

Denied events identify the requested client_id. The initial authorization-code exchange emits event 1203 and associates the client with the realm user and issued underlying token. Refresh exchanges do not emit another grant event.

Disable access

To prevent new OAuth activity while retaining the configuration, set oauth_server.enabled to false. To remove one client, delete its exact CIMD URL from allowed_clients. To deny every client, use an empty list:

{
  "oauth_server": {
    "enabled": false,
    "allowed_clients": []
  }
}

Disabling realm OAuth or removing a client prevents new authorization and token exchanges. Removing a client does not immediately revoke access Bearers already issued to it; they may remain usable until their one-hour deadline, subject to the source token's validity.

Logging out the realm user, or deleting, invalidating, or replacing the source token, invalidates its access Bearers and refresh tokens. Remove the client from allowed_clients as well when it must not start a new authorization flow. Disabling realm OAuth prevents every client from starting or refreshing authorization.

Troubleshooting

OAuth protocol failures return an error and usually an error_description:

{
  "error": "invalid_client",
  "error_description": "client is not allowed"
}

Before the client redirect URI has been retrieved and validated, errors are returned directly as JSON. After the redirect URI is trusted, authorization errors are sent to that URI with the original state.

Error Common cause
invalid_client CIMD URL is not exact, is not allowlisted, cannot be retrieved, redirects, or contains invalid metadata
invalid_request A required parameter is missing, a redirect URI is not registered, PKCE syntax is invalid, or a one-time continuation was reused
unsupported_response_type response_type is not code
unsupported_grant_type Token request is neither authorization_code nor refresh_token
invalid_scope Requested scope is not exactly default
invalid_grant Code or refresh token is expired or already used; client, redirect URI, or PKCE binding does not match; or the refresh token's source flespi token is deleted, invalid, replaced, or no longer assigned to the realm user
access_denied User or identity provider denied authorization, user or realm is disabled, or realm OAuth was disabled

Check these items in order:

  1. Confirm the realm is enabled and address it by its public ID.
  2. Confirm oauth_server.enabled is true.
  3. Compare the requested client_id byte-for-byte with allowed_clients.
  4. Retrieve the CIMD URL without following redirects and validate its JSON fields.
  5. Compare the requested callback with redirect_uris, including path, query, and native loopback port.
  6. Confirm that the verifier is the source of the request's S256 challenge.
  7. Confirm the client replaced its refresh token after the previous refresh.
  8. Inspect the realm Logs tab for denied-client and realm-user events.

Username and password failures happen in the realm login flow and may be displayed there rather than returned to the OAuth callback.

Find an unknown client ID

If a client does not document its CIMD URL, try connecting it once. When the client sends a syntactically valid HTTPS CIMD URL that is not yet allowed, the authorization request fails with invalid_client and the realm Logs tab records event 1202 with the exact requested client_id.

Verify that the URL belongs to the intended client and serves a valid CIMD before adding it to oauth_server.allowed_clients, then retry the connection. Do not allowlist a URL only because it appears in the log; any client can submit a URL. A malformed or non-HTTPS client ID is rejected before event 1202 is recorded.

Protocol limitations

Realm OAuth intentionally provides a focused public-client authorization profile. It does not currently provide:

  • OpenID Connect ID tokens, UserInfo, or login claims for clients.
  • Client secrets or other confidential-client authentication.
  • Dynamic client registration; clients are admitted through CIMD URL allowlisting.
  • Token introspection or revocation endpoints.
  • Grant types other than Authorization Code and refresh token.
  • PKCE methods other than S256.
  • Fine-grained OAuth scopes; only default is supported.
  • OAuth resource or audience binding.
  • Persistent consent grants; users approve each authorization request.

See also
Connect OAuth-capable MCP clients to a realm so users can authorize AI agents without sharing flespi tokens.
Step-by-step guide for configuring SSO (Single Sign-On) authentication using your preferred Identity Provider.