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 tenant for 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/update cannot 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:

  1. Create the record with /oauth/clients/insert.
  2. Make it confidential, when needed, with /oauth/clients/set_auth.
  3. Configure policy with /oauth/clients/set_knobs.
  4. Activate it with /oauth/clients/update_status.
  5. 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 status to draft;
  • sets token_endpoint_auth_method to none;
  • ignores policy-knob fields (use set_knobs instead);
  • fixes the tenant at creation time; and
  • defaults an empty grant_types list 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:

  • none
  • client_secret_post
  • client_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.