Skip to main content

Manage OAuth 2.0 and OpenID Connect clients

OAuth2 clients are applications that securely authenticate with the authorization server to obtain access to an HTTP service. Confidential clients can use registered client secrets to authenticate, while public clients are unable to use registered client secrets. OAuth2 clients can be configured in a secure manner using the Ory OAuth2 and OpenID Connect product. This documentation article explains how to manage OAuth2 clients using the Ory Console, Ory SDK, Ory CLI, and Ory REST APIs.

Create OAuth2 client

To create a new OAuth2 client, use the following methods:

The Ory Console is a web-based user interface that allows you to manage OAuth2 clients. To create a new client:

  1. Go to OAuth 2Clients and applications in the Ory Console
  2. Click Create OAuth2 Client and complete the form or update an existing client.
  3. When creating a confidential client, copy the client secret when printed. It is only shown once.

Update OAuth2 client

To update an existing OAuth2 client, use the following methods:

  1. Go to OAuth 2Clients and applications in the Ory Console.
  2. Locate the client you want to update.
  3. Click on the pen symbol to update the client's configuration.
  4. When you are finished, scroll to the top and click Save.

Patch OAuth2 client

To partially update an existing OAuth2 client, use the following methods:

  1. Go to OAuth 2Clients and applications in the Ory Console.
  2. Locate the client you want to update.
  3. Click on the pen symbol to update the client's configuration.
  4. When you are finished, scroll to the top and click Save.

Rotate OAuth2 client secret

OAuth2 client secret rotation allows you to change a client's secret without downtime. When you rotate a secret, the old secret remains valid until you remove it, allowing you to update all your client services without service interruption.

How secret rotation works
  1. Generate a new secret for the client service. Both the old and the new secret authenticate from this point on.
  2. Update your client services to use the new secret.
  3. Test that the client services can authenticate with the new secret.
  4. Manually remove the old secret. Only the new secret authenticates from this point on.
Rotate client secret

To rotate an OAuth2 client secret, use the following methods:

curl -X POST https://{project.slug}.projects.oryapis.com/admin/clients/{client-id}/secrets/rotate \
-H "Authorization: Bearer ory_pat_..."

The response includes the new client_secret. Ory shows this value only once. Store it immediately in the secret store that your client services read from, such as a secrets manager or an encrypted environment configuration.

See API documentation.

Remove old secret

Once all services are updated to use the new secret, remove the old secret to revoke access using the old secret:

curl -X DELETE https://{project.slug}.projects.oryapis.com/admin/clients/{client-id}/secrets/rotate \
-H "Authorization: Bearer ory_pat_..."

After removing the old secret, only the current (new) secret is valid. The old secret can no longer authenticate.

See API documentation.

Secret rotation workflow example

Here's a complete workflow for rotating a client secret:

# 1. Get current client
CLIENT_ID="your-client-id"

# 2. Rotate the secret
NEW_SECRET=$(curl -X POST "https://{project.slug}.projects.oryapis.com/admin/clients/$CLIENT_ID/secrets/rotate" \
-H "Authorization: Bearer ory_pat_..." | jq -r '.client_secret')

echo "New secret: $NEW_SECRET"

# 3. Update your client services with the new secret
# (Both the old and the new secret work during this period)

# 4. Verify the new secret works
curl -X POST "https://{project.slug}.projects.oryapis.com/oauth2/token" \
-u "$CLIENT_ID:$NEW_SECRET" \
-d "grant_type=client_credentials"

# 5. Once all client services are updated, remove the old secret
curl -X DELETE "https://{project.slug}.projects.oryapis.com/admin/clients/$CLIENT_ID/secrets/rotate" \
-H "Authorization: Bearer ory_pat_..."

# Old secret is now revoked
Zero-downtime credential rotation

Secret rotation enables zero-downtime credential updates. Both the old and new secrets remain valid until you manually remove the old secret, allowing you to update all your client services without service interruption.

Security best practice

Secrets remain valid indefinitely until you explicitly remove them. Always remove old secrets once your secret rotation process is complete to ensure that compromised credentials cannot be used.

Delete OAuth2 client

To delete an existing OAuth2 client, use the following methods:

  1. Go to OAuth 2Clients and applications in the Ory Console.
  2. Locate the client you want to update.
  3. Click on pen symbol to update the client's configuration.
  4. Scroll to the bottom and click Delete Client.

OpenID Dynamic Client Registration

OpenID Dynamic Client Registration enables automatic registration of OAuth2 clients with the authorization server. When enabled, clients can be created, retrieved, updated, patched, and deleted dynamically without manual configuration. To enable OpenID Dynamic Client Registration, use the Ory CLI:

ory patch oauth2-config --project <project-id> --workspace <workspace-id>
--replace "/oidc/dynamic_client_registration/enabled=true"

OpenID Connect dynamic registration involves the use of a registration_access_token, which is a bearer token that allows a client to make requests to the OpenID Connect dynamic registration endpoint. The token is issued by the authorization server and can only be used by the client that it was issued to.

It's important to note that the registration_access_token is a sensitive piece of information that should be kept secure. It should only be used by the client that it was issued to and should not be shared with any other parties.

Register OAuth2 and OpenID Connect clients

Use the SDK or REST API to register an OAuth2 and OpenID Connect client:


import { Configuration, OidcApi } from "@ory/client"

const ory = new OidcApi(
new Configuration({
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
accessToken: process.env.ORY_API_KEY,
}),
)

export async function createOidcDynamicClient() {
const { data } = await ory.createOidcDynamicClient({
oAuth2Client: {
grant_types: ["authorization_code", "refresh_token"],
redirect_uris: ["https://example.com"],
scope: "offline openid",
token_endpoint_auth_method: "client_secret_post",
},
})

console.log(data.registration_access_token) // Write this down, it is only sent once!
console.log(data.client_id, data.client_secret /* ... */)
}

The response includes the registration_access_token which is needed to manage the client. The token will only be shown once!

Get OAuth2 and OpenID Connect clients

The GET endpoint requires the client to authenticate with the registration_access_token regardless of the token_endpoint_auth_method. It can be used to retrieve the OAuth2 and OpenID Connect client.


import { Configuration, OidcApi } from "@ory/client"

const ory = new OidcApi(
new Configuration({
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
accessToken: process.env.ORY_API_KEY,
}),
)

export async function getOidcDynamicClient(
id: string,
registrationAccessToken: string,
) {
const { data } = await ory.getOidcDynamicClient(
{
id,
},
{
headers: {
Authorization: `Bearer ${registrationAccessToken}`,
},
},
)
}

Update OAuth2 and OpenID Connect clients

The POST endpoint requires the client to authenticate with the registration_access_token regardless of the token_endpoint_auth_method. It can be used to update the OAuth2 and OpenID Connect client.


import { Configuration, OAuth2Client, OidcApi } from "@ory/client"

const ory = new OidcApi(
new Configuration({
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
accessToken: process.env.ORY_API_KEY,
}),
)

export async function createOidcDynamicClient(
id: string,
updatedClient: OAuth2Client,
) {
const { data } = await ory.setOidcDynamicClient({
id: id,
oAuth2Client: {
...updatedClient,
grant_types: ["authorization_code", "refresh_token"],
// ...
},
})

console.log(data.registration_access_token) // Write this down, it is only sent once!
}

Delete OAuth2 and OpenID Connect clients

The DELETE endpoint requires the client to authenticate with the registration_access_token regardless of the token_endpoint_auth_method. It can be used to delete the OAuth2 and OpenID Connect client.


import { Configuration, OidcApi } from "@ory/client"

const ory = new OidcApi(
new Configuration({
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
accessToken: process.env.ORY_API_KEY,
}),
)

export async function deleteOidcDynamicClient(
id: string,
registrationAccessToken: string,
) {
await ory.deleteOidcDynamicClient(
{
id,
},
{
headers: {
Authorization: `Bearer ${registrationAccessToken}`,
},
},
)
}

Example OAuth2 clients

Here are some examples of creating OAuth2 clients with different options:

Client credentials

ory create oauth2-client \
--grant-type client_credentials \
--scope my-scope \
--token-endpoint-auth-method client_secret_basic

Token endpoint auth method

ory create oauth2-client \
--grant-type authorization_code \
--response-type code \
--scope openid \
--token-endpoint-auth-method client_secret_post \
--redirect-uri https://my-app.com/callback

Multiple redirect URIs

ory create oauth2-client \
--grant-type authorization_code --grant-type refresh_token \
--response-type code \
--scope openid --scope offline_access \
--token-endpoint-auth-method client_secret_post \
--redirect-uri https://my-app.com/callback --redirect-uri http://my-other-app.com/callback