OAuth client management
Use this API family to create and manage OAuth application registrations, set their policy, and manage application-to-application connections. For standard OAuth and OpenID Connect authorization, token, device-authorization, and registration protocol endpoints, use the M7 SSO API documentation.
Access and identifiers
Personal applications belong to the signed-in consumer user. Organization applications belong to an organization where the signed-in consumer user has active Management-group access. Organization application tokens do not manage OAuth client records through this family. See the authorization guide for the complete principal rules.
OAuth-app routes use two identifiers:
| Identifier | Used by | Meaning |
|---|---|---|
id |
Most api.user application routes |
The OAuth application record UUID. |
client_id |
OAuth protocol requests and /org/manage/add with type: "app" |
The public OAuth client identifier. |
Do not substitute client_id for id on /oauth/clients/view, update,
set_auth, set_knobs, set_groups, or lifecycle routes.
Tenant context
The optional tenant field selects an application-management context.
- Omit
tenantfor the signed-in user's personal applications. - Send an organization UUID to work with applications in an organization the caller can manage.
- An application receives its tenant when it is inserted;
/oauth/clients/updatecannot move it to another tenant.
Use /oauth/clients/tenants to list accessible personal and organization
contexts. Use /oauth/clients/tenant-info with an optional tenant to inspect
the current context.
Application lifecycle
An application registration is created as a draft. A typical setup sequence is:
- Create the record with
/oauth/clients/insert. - Make it confidential, when needed, with
/oauth/clients/set_auth. - Configure policy with
/oauth/clients/set_knobs. - Activate it with
/oauth/clients/update_status. - For organization applications, configure registration and login groups with
/oauth/clients/set_groups.
Core application routes
| Route | Required fields | Behavior |
|---|---|---|
/oauth/clients/insert |
None strictly; send name and usually registration fields |
Creates a draft record and generates its client_id. |
/oauth/clients/view |
id |
Returns one application, including config, knobs, and resolved groups. |
/oauth/clients/search |
None | Lists applications in the selected tenant context. Supports shared pagination. |
/oauth/clients/update |
id |
Partial update of registration metadata. Cannot change tenant, client auth, or knobs. |
/oauth/clients/delete |
id |
First call archives the record (ARCHIVE); an archived record with the required lock confirmation is permanently deleted (DELETE). |
/oauth/clients/recover |
id |
Restores an archived record. |
/oauth/clients/update_status |
id, status |
Sets lifecycle status: draft, active, or disabled. |
/oauth/clients/set_auth |
id, token_endpoint_auth_method |
Sets the token-endpoint authentication method. |
/oauth/clients/set_knobs |
id |
Partially updates token and hosted-application policy fields. |
/oauth/clients/set_groups |
id, register and/or login |
Sets organization-application registration and login groups. |
/oauth/clients/set_config_lock |
id, config_lock_hash_new |
Sets, replaces, or clears a configuration lock. |
/oauth/clients/tenants |
None | Lists accessible tenant contexts. |
/oauth/clients/tenant-info |
None | Optional tenant; omitting it selects the personal context. |
Create an application
insert creates a registration, not a ready-to-use OAuth client. The API:
- generates the public
client_id; callers cannot choose it; - sets
statustodraft; - sets
token_endpoint_auth_methodtonone; - ignores policy-knob fields (use
set_knobsinstead); - fixes the tenant at creation time; and
- defaults an empty
grant_typeslist to["authorization_code"]and enables PKCE by default.
Use name for the application name. These list fields accept JSON arrays or
newline-separated strings: redirect_uris, post_logout_redirect_uris,
grant_types, ip_whitelist, and response_types. audiences is accepted as
an alias for allowed_audiences.
curl -sS https://api.user.m7.org/api/v2/oauth/clients/insert \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"name": "Example App",
"redirect_uris": ["https://app.example.com/callback"],
"grant_types": ["authorization_code"],
"tenant": "ORG_UUID"
}'
{
"status": 1,
"comment": "INSERT",
"data": {
"id": "OAUTH_CLIENT_RECORD_UUID",
"client_id": "PUBLIC_CLIENT_ID",
"name": "Example App",
"status": "draft",
"token_endpoint_auth_method": "none",
"require_pkce": true
}
}
View an application
curl -sS https://api.user.m7.org/api/v2/oauth/clients/view \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{ "id": "OAUTH_CLIENT_RECORD_UUID" }'
Registration fields
Use /oauth/clients/update for partial changes to main registration metadata.
The endpoint accepts registration fields such as name, issuer,
application_type (web, spa, native, or machine), redirect_uris,
post_logout_redirect_uris, grant_types, response_types,
allowed_audiences, allowed_scopes, ip_whitelist, require_pkce,
dpop_policy, initiate_login_uri, default_max_age, notes, and expires.
update cannot change tenant, client_secret,
token_endpoint_auth_method, or policy knobs. Use set_auth and set_knobs
for those operations.
Make an application confidential
Use set_auth to create or change client authentication. The currently
supported direct-registration methods are:
noneclient_secret_postclient_secret_basic
For client_secret_post and client_secret_basic, also send a caller-chosen
client_secret. The API stores a password hash; it does not generate a secret
or return a usable plaintext secret. Generate the secret in your application,
store it securely when you make this call, and use that same value at the SSO
token endpoint.
| Field | Required | Notes |
|---|---|---|
id |
Yes | OAuth application record UUID. |
token_endpoint_auth_method |
Yes | none, client_secret_post, or client_secret_basic. |
client_secret |
Required for a client-secret method | Caller-chosen plaintext secret. It is stored as a hash and is not returned as plaintext. |
curl -sS https://api.user.m7.org/api/v2/oauth/clients/set_auth \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"id": "OAUTH_CLIENT_RECORD_UUID",
"token_endpoint_auth_method": "client_secret_post",
"client_secret": "STORE_THIS_SECRET_SECURELY"
}'
The success comment is SET_AUTH. Changing to a client-secret method makes
the application confidential.
{
"status": 1,
"comment": "SET_AUTH",
"data": {
"id": "OAUTH_CLIENT_RECORD_UUID",
"client_id": "PUBLIC_CLIENT_ID",
"token_endpoint_auth_method": "client_secret_post"
}
}
Activate an application
curl -sS https://api.user.m7.org/api/v2/oauth/clients/update_status \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"id": "OAUTH_CLIENT_RECORD_UUID",
"status": "active"
}'
The success comment is UPDATE_STATUS.
Policy knobs and configuration locks
Use /oauth/clients/set_knobs with the application record id and only the
values to change. It supports the same token TTL, claim, and
tenant_policy_* application-policy fields as organization policy knobs.
null or "" removes an optional application override.
Application policy values override organization values when set. view,
search, and set_knobs return policy data in both config and the filtered
knobs map.
curl -sS https://api.user.m7.org/api/v2/oauth/clients/set_knobs \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"id": "OAUTH_CLIENT_RECORD_UUID",
"access_token_ttl_default": 900,
"access_token_ttl_mutable": true
}'
The success comment is SET_KNOBS.
A configuration-locked application requires its current config_lock_hash on
protected configuration changes, including update, set_auth, set_knobs,
and set_groups. To set or clear the lock, send config_lock_hash_new to
/oauth/clients/set_config_lock; send null to clear it. If a lock already
exists, also send the current config_lock_hash to confirm the operation.
Registration and login groups
/oauth/clients/set_groups applies only to an organization application.
| Field | Required | Meaning |
|---|---|---|
id |
Yes | OAuth application record UUID. |
register |
One of register or login |
Group UUIDs or slugs that control the registration group list. |
login |
One of register or login |
Group UUIDs or slugs that control the login group list. |
Omit one list to leave it unchanged. Send null or [] to clear a list.
Groups must be active, unarchived, unexpired, and in the application's tenant.
The response returns resolved records in data.groups.register and
data.groups.login.
curl -sS https://api.user.m7.org/api/v2/oauth/clients/set_groups \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"id": "OAUTH_CLIENT_RECORD_UUID",
"register": ["GROUP_UUID"],
"login": ["operators"]
}'
The success comment is SET_GROUPS.
Application connections
A connection joins a consumer application to a provider application. The three route families expose the same connection record from different perspectives:
| Family | Perspective |
|---|---|
/oauth/clients/connections/* |
Shared connection record; callers with consumer or provider access can use it. |
/oauth/clients/connected/* |
Consumer-side view and management. |
/oauth/clients/authorized/* |
Provider-side view and status decisions. |
Shared connection routes
| Route | Required fields | Notes |
|---|---|---|
/oauth/clients/connections/insert |
consumer_cid, audience |
Optional tenant; provider is resolved from provider_cid or provider_client_id. New records start pending; consumer and provider must differ. |
/oauth/clients/connections/search |
None | Filters: id, consumer_cid, provider_cid, provider_client_id, status, archived, and side (consumer or provider). status: "all" removes the status filter. |
/oauth/clients/connections/view |
id |
Returns one connection. |
/oauth/clients/connections/update |
id |
Cannot change provider, consumer, audience, or status. An empty patch fails with nothing to update. |
/oauth/clients/connections/update_status |
id, status |
Provider-side decision. Allowed statuses: pending, active, paused, declined, revoked. |
/oauth/clients/connections/delete |
id |
Optional archived. |
/oauth/clients/connections/recover |
id |
Restores an archived connection. |
/oauth/clients/connections/verify |
token, plus provider_cid or provider_client_id |
No bearer token required. Verifies the token against the current provider connection. |
Create a connection
curl -sS https://api.user.m7.org/api/v2/oauth/clients/connections/insert \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"consumer_cid": "CONSUMER_RECORD_UUID",
"audience": "https://api.example.m7.org",
"provider_client_id": "PROVIDER_PUBLIC_CLIENT_ID"
}'
The response uses comment: "INSERT" and returns the pending connection in
data.
Decide a connection request
curl -sS https://api.user.m7.org/api/v2/oauth/clients/connections/update_status \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"id": "CONNECTION_UUID",
"status": "active"
}'
This returns comment: "UPDATE_STATUS".
Verify a connection token
/oauth/clients/connections/verify is the one documented route in this service
that does not use the caller's Bearer token. Send the token to inspect in the
JSON body together with either the provider application record ID
(provider_cid) or its public OAuth identifier (provider_client_id).
curl -sS https://api.user.m7.org/api/v2/oauth/clients/connections/verify \
-H 'Content-Type: application/json' \
-d '{
"token": "ACCESS_TOKEN_TO_VERIFY",
"provider_client_id": "PROVIDER_PUBLIC_CLIENT_ID"
}'
A completed check returns comment: "VERIFY". Inspect data.allowed and
data.token_valid; a cryptographically valid token can still have
allowed: false when the consumer, audience, connection status, or approved
scope relationship does not match.
Consumer and provider route families
/oauth/clients/connected/* is the consumer-side surface:
| Route | Required fields | Notes |
|---|---|---|
/oauth/clients/connected/search |
None | Optional id, consumer_cid, status, archived, tenant, and shared pagination. status: "all" removes the status filter. |
/oauth/clients/connected/insert |
consumer_cid, audience |
Optional tenant; provider is resolved from provider_cid or provider_client_id. Creates a pending record. |
/oauth/clients/connected/view |
id |
Returns one consumer-side connection. |
/oauth/clients/connected/update |
id |
Updates connection metadata only; provider, consumer, audience, and status are immutable here. |
/oauth/clients/authorized/* is the provider-side surface:
| Route | Required fields | Notes |
|---|---|---|
/oauth/clients/authorized/search |
None | Optional id, provider_cid, provider_client_id, status, archived, tenant, and shared pagination. status: "all" removes the status filter. |
/oauth/clients/authorized/view |
id |
Returns one provider-side connection. |
/oauth/clients/authorized/update |
id |
Updates connection metadata only; provider, consumer, audience, and status are immutable here. |
/oauth/clients/authorized/update_status |
id, status |
Provider-side status decision. Use pending, active, paused, declined, or revoked. |
Search responses
/oauth/clients/search, connection searches, and related issued-record
searches use the shared pagination contract. Without
pagination fields, data is an array. With pagination fields, data.items
contains the records alongside page metadata.