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
- Prerequisites
- Configure the OAuth client
- Enable realm OAuth
- Connect an OAuth client
- Tokens and permissions
- Security and audit
- Disable access
- Troubleshooting
- Protocol limitations
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:
- Create and configure a realm.
- Create at least one enabled realm user or configure an identity provider that can authenticate or register realm users.
- Configure the realm role or user token parameters with the minimum access the application needs.
- 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_idis required and must exactly match the URL from which the document is retrieved.redirect_urisis required and must contain at least one URI.client_nameis optional. If present, flespi displays it on the consent dialog.application_typemay bewebornativeand defaults toweb.- If
response_typesis present, it must includecode. - If
grant_typesis present, it must includeauthorization_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:
- Confirm the realm is enabled and address it by its public ID.
- Confirm
oauth_server.enabledistrue. - Compare the requested
client_idbyte-for-byte withallowed_clients. - Retrieve the CIMD URL without following redirects and validate its JSON fields.
- Compare the requested callback with
redirect_uris, including path, query, and native loopback port. - Confirm that the verifier is the source of the request's S256 challenge.
- Confirm the client replaced its refresh token after the previous refresh.
- 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
defaultis supported. - OAuth resource or audience binding.
- Persistent consent grants; users approve each authorization request.