Register a new OAuth client
/api/v1/oauth-clientsRegisters a new confidential OAuth client in the current Environment with the given name, redirect_uris, and optional scopes (defaulting to openid profile email), each one of openid, profile, email, org and permissions; any other value is refused with 400 (oauth.client_scope_unknown). With client_kind: machine it registers a machine client instead: a principal of its own that holds roles (see the assignments routes) and obtains tokens for itself, with an optional organization_node_id (the one organization it acts in), optional allowed_audiences and the permissions scope, the client_credentials grant only and no redirect URIs; it counts toward the plan's machine-credential allowance (409 plan_limit_exceeded). Generates the client_id and a client_secret that is bcrypt-hashed at rest; the raw secret is returned in this response only and is never retrievable again. Responds 201 Created.
Authentication
Authorization Option A JWT access token. Never send alongside X-API-Key: a request carrying both is refused.
X-API-Key Option B API key for management-tier access. Never send alongside an Authorization header: a request carrying both is refused.
Request body
application/json
namestring Required client_kindenum Optional `web` (when omitted): a person signs in through this client with the authorization code grant. `machine`: the client is a principal of its own that holds roles and obtains tokens for itself with the `client_credentials` grant, for the audiences it lists, inside at most one organization; it takes no redirect URIs or sign-in fields.
organization_node_idstring Optional Machine clients only: the organization the client acts in. Its tokens name it and it may hold roles only inside it. Omitted, the client acts across the Environment.
allowed_audiencesstring[] Optional For a machine client: the audiences (your APIs' identifiers) it may request a token for with `audience`, beside the Environment's `m2m_default_audience`. The token's `aud` names the one asked for.
redirect_urisstring[] Optional Required for a web client; a machine client has none.
post_logout_redirect_urisstring[] Optional Where this client may send someone after RP-initiated logout. Matched exactly, and separate from `redirect_uris`: receiving an authorization code and being a landing page after sign-out are different kinds of trust.
scopesstring[] Optional What the client's tokens may carry. Omitted, a web client gets `openid`, `profile` and `email`; a machine client gets `permissions`, the only scope it may hold.
backchannel_logout_uristring Optional Where Canopy delivers a signed logout token, server to server, when a session this client issued tokens for ends. Omit it and the client is told nothing.
invite_redirect_urlstring Optional initiate_login_uristring Optional The route in your application that starts a sign-in (OpenID Connect `initiate_login_uri`): it should send the person to Canopy's `/oauth/authorize`. Canopy's hosted pages that end with nothing to return to, such as an accepted invitation or a verified email, offer it as **Sign in**. Absolute `http` or `https` URL.
Responses
application/json
data *OAuthClientCreatedResponseDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
application/json
error *ApiErrorBodyDto
Idempotency
Idempotency-Key header
Send an Idempotency-Key header to make retries safe. Canopy replays the same response for matching keys within 24 hours, and refuses the same key sent with a different request with 422 idempotency.key_reused_with_different_request.
Returned object
curl -X POST "https://auth.canopy-io.com/api/v1/oauth-clients" \ -H "X-API-Key: $CANOPY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "client_kind": "web", "organization_node_id": "string", "allowed_audiences": [ "https://api.example.com" ], "redirect_uris": [ "string" ], "post_logout_redirect_uris": [ "string" ], "scopes": [ "string" ], "backchannel_logout_uri": "string", "invite_redirect_url": "string", "initiate_login_uri": "string" }'
{ "data": { "id": "string", "client_id": "string", "name": "string", "client_kind": "web", "organization_node_id": "string", "organization_name": "string", "allowed_audiences": [ "string" ], "redirect_uris": [ "string" ], "post_logout_redirect_uris": [ "string" ], "grant_types": [ "string" ], "scopes": [ "string" ], "backchannel_logout_uri": "string", "invite_redirect_url": "string", "initiate_login_uri": "string", "is_active": false, "created_at": "2026-04-20T12:00:00.000Z", "issuer": "https://auth.yourapp.com", "client_secret": "string" } }
Tell us how we can improve this guide.