How to register an OAuth 2.0 client / OpenID Connect relying party

  1. Why register clients?
  2. The client registration endpoint
  3. Access to the registration endpoint
  4. Examples
  5. References
  6. Frequently asked questions (FAQ)

1. Why register clients?

A client application must be registered with the Connect2id server before it can request tokens from it.

First and foremost this establishes the credentials to identify and / or authenticate the client in requests to the server. Second, establishes crucial security settings, such as the preferred signing algorithm for ID tokens issued to it. Without these there won't be enough context to process the requests, as the OAuth requests are designed in general to be minimal and carry few parameters.

The registrant, which can be the developer, an administrator, or the client software itself (yes, automated self-registration is possible) needs to give several pieces of information:

  • The methods, or grant types in OAuth jargon, that the client will use to obtain the tokens. Depending on the grant type, additional parameters may be required, such as a callback URL to receive authorisation codes for the authorization_code grant type.

  • The preferred client authentication method (e.g. shared secret or private key based) and security algorithms for the ID tokens and other objects passed between client and server, unless the client wants to stick with the default ones (client_secret_basic auth and RS256 for the ID token signatures).

  • Metadata, such as the application's name, logo and terms of service, to be displayed in the login / consent UI of the Connect2id server. These are not mandatory for the protocol, but meant to improve the user experience.

Note that the server's security policy and configuration dictates what parameters will ultimately get registered. If a certain parameter is not supported or permitted, the server will try to provide a suitable default. If a parameter is found to be invalid an error will be returned.

For a successfully registered client the Connect2id server will provision:

  • A unique client ID;

  • A special registration access token to enable the client application to read, modify or delete its registration, or to refresh the client secret. Must be kept safe.

2. The client registration endpoint

Clients are registered at the registration_endpoint advertised in the Connect2id server metadata. Its URL has this form:

https://[base-server-url]/clients/

3. Access to the registration endpoint

Unless open registration is permitted by the server, a token is required to register a new client. This can be the configured master token for the client registration endpoint, or a specially provisioned one-time use token.

Note, even with enabled open registration, a token is required to register a client for certain OAuth 2.0 grant types (such as password or client_credentials), or to set the scope client field.

The access token, of type bearer, must be passed with the Authorization header of the HTTP request:

Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

If the token is missing and open registration is disabled, the server will respond with the following error:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

Here's the error for an invalid token:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token", error_description="Invalid access token"

4. Examples

Let's now register several example clients with the demo Connect2id server, which permits open registration and has its client registration endpoint at

Endpoint URL https://demo.c2id.com/clients/

4.1 Minimal registration

To register an OpenID Connect client for the default code flow it suffices to specify the redirection URL where the client expects to receive logged-in end-users with the authorisation code generated by the Connect2id server. A registration token is required unless open registration is permitted.

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris" : [ "https://client.example.org/callback" ]
}

With curl:

curl -s -XPOST -H "Content-Type:application/json" \
-H "Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6" \
-d '{"redirect_uris":["https://client.example.org/callback"]}' \
https://demo.c2id.com/clients

To post the client metadata from a text file instead of inlined prefix @ to the file name:

curl -s -XPOST -H "Content-Type:application/json" \
-H "Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6" \
-d @client-metadata.json \
https://demo.c2id.com/clients

Successful registration is indicated by a 200 or 201 HTTP status. The response body will contain a JSON object with the registered and provisioned parameters for the client.

As explained in the introduction, the server will provision the following important parameters for the client:

  • The client_id and client_secret credentials to authenticate the client in future login and token requests. The secret, as the name implies, must be stored securely!

  • The registration URI and access token to read, modify or delete the client registration later, in a RESTful manner. The token must also be stored securely. Alternatively, the registration token can be simply discarded; if some client detail needs to be modified a new registration can be made, and the client switched to the newly provisioned client_id.

Certain parameters will assume the following default values if not explicitly specified in the registration request:

  • The client will be registered for the OAuth 2.0 authorization_code grant type and the code response type. Note, to allow the client to receive refresh tokens it must be explicitly registered for the refresh_token grant.

  • The client authentication method at the token endpoint will be client_secret_basic.

  • ID tokens issued to the client will be signed using the server's public RSA JSON Web Key (JWK) and the RS256 algorithm.

Other parameters matter less; you can read about them in the OpenID Connect spec and the applicable OAuth 2.0 and OpenID Connect extensions.

The response will confirm the registered callback URL. If necessary multiple callback URLs can be registered (redirect_uris).

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "client_id"                    : "5def774h6caci",
  "client_id_issued_at"          : 1412671298,
  "client_secret"                : "AITXP49gecnFP83u1Mjot9xz7Hgu4u4lYBrTxvNtq1k",
  "client_secret_expires_at"     : 0,
  "registration_client_uri"      : "https://demo.c2id.com/clients/5def774h6caci",
  "registration_access_token"    : "jZNmlyJeo3V2j14fynmDthWjbizNYe2fc5pYW27fReo",
  "grant_types"                  : [ "authorization_code" ],
  "response_types"               : [ "code" ],
  "redirect_uris"                : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"   : "client_secret_basic",
  "application_type"             : "web",
  "subject_type"                 : "public",
  "id_token_signed_response_alg" : "RS256",
  "require_auth_time"            : false
}

If the request is invalid or malformed a 400 Bad Request error is returned:

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "error"             : "invalid_redirect_uri",
  "error_description" : "Invalid redirection URI(s): Redirection URIs must have a schema"
}

4.2 Allow refresh tokens

To allow a client in the code flow to receive refresh tokens it must be explicitly registered for the refresh_token grant (in addition to authorization_code), otherwise the client may only request access and ID tokens:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris" : [ "https://client.example.org/callback" ],
  "grant_types"   : [ "authorization_code", "refresh_token" ]
}

4.3 Client details to display to end-users

When the user's browser is sent to the login page (technically the authorisation endpoint) of the Connect2id server, to help the end-user recognise the client application but also for legal purposes, it is helpful to display the application's name, logo and legal links.

The client registration specs define several parameters for that:

  • client_name -- The name of the client app. This parameter should always be provided.

  • logo_uri -- The logo or icon URL of the client. Must point to a suitable image to be displayed in the browser. Also good to have.

  • client_uri -- Link to the home page of the client.

  • policy_uri -- Link to the privacy policy document.

  • tos_uri-- Link to the terms-of-service document.

To cater for international audiences the client details can be provided in multiple locales, by appending language tags to the parameter names:

"client_name#en" : "My Express Shop",
"client_name#es" : "Mi Tienda Exprés"

Let's now register another client, and provide its name, logo and other details:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris" : [ "https://client.example.org/callback" ],
  "client_name"   : "My Example App",
  "logo_uri"      : "http://client.example.org/logo.png",
  "client_uri"    : "http://client.example.org",
  "policy_uri"    : "http://client.example.org/privacy-policy.html",
  "tos_uri"       : "http://client.example.org/terms-of-service.html"
}

The server response with the registration confirmation:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "client_id"                    : "ug2sb5zkcmpsi",
  "client_id_issued_at"          : 1412692755,
  "client_secret"                : "DUdXNieQ8fwF07surrra8htYc5f_yED0MxuM21yw7W8",
  "client_secret_expires_at"     : 0,
  "registration_client_uri"      : "https://demo.c2id.com/clients/ug2sb5zkcmpsi",
  "registration_access_token"    : "5YHead_Ir8rNQP2KYW31XZHvca7Xk0qi6HKoS-OoTZg",
  "grant_types"                  : [ "authorization_code" ],
  "response_types"               : [ "code" ],
  "redirect_uris"                : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"   : "client_secret_basic",
  "client_name"                  : "My Example App",
  "logo_uri"                     : "http://client.example.org/logo.png",
  "client_uri"                   : "http://client.example.org",
  "policy_uri"                   : "http://client.example.org/privacy-policy.html",
  "tos_uri"                      : "http://client.example.org/terms-of-service.html",
  "application_type"             : "web",
  "subject_type"                 : "public",
  "id_token_signed_response_alg" : "RS256",
  "require_auth_time"            : false
}

4.4 How to register a public client

OAuth defines two types of clients:

  • Confidential -- clients that can maintain the confidentiality of credentials that are issued to them (which is typically all server-based software).
  • Public -- clients that cannot be securely verified by the OAuth / OpenID Connect server as they cannot keep client credentials issued to them confidential (typically all clients that are installed on end-user devices, or web-browser based apps). Instances of such clients may share the same same client_id (such as all instances of a mobile app downloaded from an app store).

Unless specifically requested, clients will be registered as confidential and issued a client secret (alternative client credentials are available).

Before registering a public client, make sure the Connect2id server is configured to include none in the list of the supported client authentication methods.

To register a public client set the token endpoint authentication method to none. Public clients must be required to use a code challenge (PKCE, see RFC 7636), to prevent code injection (replay) and other attacks.

Example registration request for a public native client (mobile app using the code flow and a custom redirection URI):

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "application_type"           : "native",
  "redirect_uris"              : [ "com.example.app:///auth" ],
  "token_endpoint_auth_method" : "none",
  "code_challenge_method"      : "S256"
}

Note, the application type must be explicitly set to native to register a redirection URI with a custom scheme, or localhost as the host name.

Example registration request for a public web client (JavaScript app):

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "grant_types"                : [ "authorization_code", "refresh_token" ],
  "response_types"             : [ "code" ],
  "redirect_uris"              : [ "https://myapp.example.com/?callback" ],
  "token_endpoint_auth_method" : "none",
  "code_challenge_method"      : "S256"
}

4.5 How to register a native (mobile, desktop) client

Native applications must indicate their type in the application_type metadata parameter, by setting it to native, otherwise the Connect2id server will assume a web application.

Native applications are allowed to register the following types of redirect_uris:

  • http URLs with a localhost or loopback IP -- 127.0.0.1 in IPv4 or 0:0:0:0:0:0:0:1 (short form ::1) in IPv6. The port may be variable (see more on that below).

  • https URLs (may be claimed).

  • URIs with custom URI schemes.

For testing purposes a native application may be excepted from the https requirement for web host redirection URLs, by setting the op.reg.rejectNonTLSRedirectionURIs configuration property to false.

Note that a native application also has the choice to register as a confidential client (each instance receiving a unique client_id and being required to authenticate with a client credential at the token endpoint), or as a public client (all instances sharing the same client_id, no client credential).

Public clients must be required to use a code challenge (PKCE, see RFC 7636), to prevent code injection (replay) and other attacks.

Example registration request for a public native client with a custom scheme redirect URI:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "application_type"           : "native",
  "redirect_uris"              : [ "com.example.app:///auth" ],
  "token_endpoint_auth_method" : "none",
  "code_challenge_method"      : "S256"
}

Example for a public native client with an HTTP localhost redirect URL:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "application_type"           : "native",
  "redirect_uris"              : [ "http://localhost:9090/cb" ],
  "token_endpoint_auth_method" : "none",
  "code_challenge_method"      : "S256"
}

In cases when the native application is not guaranteed to be able to bind to a predetermined port, it should register for a variable port redirect_uri, by setting the port number to zero (0):

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "application_type"           : "native",
  "redirect_uris"              : [ "http://localhost:0/cb" ],
  "token_endpoint_auth_method" : "none",
  "code_challenge_method"      : "S256"
}

Authorisation requests can then use any port in the 1 to 65535 range, provided the other components in the redirection URI match the registered URI exactly.

4.6 How to register for specific OAuth 2.0 grant types or response types

If the registration request doesn't specify explicit OAuth 2.0 grant types the assumed value is authorization_code. As for the response types, they default to the single code value.

A client may 4 for other grant / response types, provided the Connect2id server is prepared to handle them. This can be checking in the advertised provider metadata, which the demo server has published at

https://demo.c2id.com/.well-known/openid-configuration

Let's register an OpenID Connect client for the implicit grant. This grant provides a simplified authorisation flow and is intended for clients implemented in a browser with scripting language such as JavaScript. Matching response types for the implicit grant type are id_token and id_token token:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"  : [ "https://client.example.org/callback" ],
  "grant_types"    : [ "implicit" ],
  "response_types" : [ "id_token", "token id_token" ]
}

Avoid registering a client for multiple grant types, for example both authorization_code and implicit, as this may lead to unwanted side effects. If a client needs to make use of more than one grant / flow, create separate registrations (client_id instances) for each one.

4.7 How to register a client for the password grant

Use of the password grant carries higher security risks. Registration for it requires the configured master token for the client registration endpoint, or a specially provisioned one-time token.

Minimal registration request for the password grant:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types" : [ "password" ]
}

The scope parameter can be used to convey special information to the password grant handler, e.g. the range of scope values that the client is authorised to use:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types" : [ "password" ],
  "scope"       : "openid email app:read app:write"
}

4.8 How to register a client for the client credentials grant

The client credentials grant is intended for clients that act on their own behalf (the client is also the resource owner), as opposed to the general OAuth case where the client acts on behalf of an end-user. This grant type is often used in microservice and B2B service scenarios.

An initial registration token is always required.

Minimal registration request:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types" : [ "client_credentials" ]
}

As with the password grant client, the scope parameter can be required by the grant handler to bound the permitted access for the client:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types" : [ "client_credentials" ],
  "scope"       : "myapi:post myapi:get myapi:delete"
}

JWT and mutual TLS based authentication at the token endpoint is recommended for best security. Example registration for a client which is going to authenticate with a JWT signed with an EC private key using the EC256 algorithm, the client's public key(s) for validating the JWT signature are published at an URL:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types"                     : [ "client_credentials" ],
  "token_endpoint_auth_method"      : "private_key_jwt",
  "token_endpoint_auth_signing_alg" : "EC256",
  "jwks_uri"                        : "https://client.example.com/jwks.json",
  "scope"                           : "myapi:post myapi:get myapi:delete"
}

4.9 How to register a client for the token exchange grant

The token exchange grant lets clients obtain an access or ID token (with optional refresh token) in exchange for some valid and recognised token, which can be local or come from a third party domain. The exchange properties and logic are controlled by means of a configurable plugin.

An initial registration token is always required.

Minimal registration request enabling the client to submit tokens for exchange:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types" : [ "urn:ietf:params:oauth:grant-type:token-exchange" ]
}

When the client is issued with a refresh token for a successful exchange it must also be registered for the refresh token grant. Otherwise the client won't be able to use the refresh token.

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types" : [ "urn:ietf:params:oauth:grant-type:token-exchange",
                    "refresh_token" ]
}

4.10 How to register a grant-less client

The Connect2id server supports registration of special "grant-less" clients that will not be using the standard token endpoint, for instance clients to be issued tokens via the direct authorisation endpoint.

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types"    : [ ],
  "response_types" : [ ]
}

4.11 How to require use of PKCE

The Proof Key for Code Exchange by OAuth Public Clients (PKCE) is a security extension originally devised to prevent code injection attacks on clients that cannot authenticate at the token endpoint, and which was later found to be useful against other attack vectors and thus became mandatory in OAuth 2.1.

To require a client to use the recommended S256 code challenge method:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris"         : [ "https://client.example.org/callback" ],
  "code_challenge_method" : "S256"
}

The code_challenge_method metadata field became available v13.0.

4.12 How to register a client for JWT authentication

JSON Web Token (JWT) assertions, specified in RFC 7523 as well as in section 9 of OpenID Connect, is a secure method for authenticating clients at the token endpoint. Instead of sending a password (the client secret) along with each request, which is how basic authentication works, the client generates a cryptographic proof of key possession.

The proof is encoded as a JWT which carries following claims:

  • iss The JWT issuer, which is represented by the client_id.
  • sub The JWT subject, which is again set to the client_id.
  • aud The JWT audience, set to the token endpoint URL.
  • exp The JWT expiration.
  • iat The JWT issue time (optional).
  • jti A unique identifier for the JWT.

Example JWT claims:

{
  "iss" : "oe7aiz60",
  "sub" : "oe7aiz60",
  "aud" : "https://demo.c2id.com/token",
  "exp" : 1453021544,
  "jti" : "Eefaevo0"
}

There are two types of JWT authentication, depending on the key used to secure the assertion:

  • client_secret_jwt -- The JWT is secured with a Hash-based Message Authentication Code (HMAC) computed with the client_secret.

  • private_key_jwt -- The JWT is signed with an asymmetric key (RSA or EC) that belongs to the client.

The server authenticates the client by verifying the HMAC with the registered client_secret (for client_secret_jwt) or by checking the RSA / EC signature with the client's registered public key (for private_key_jwt). The JWT issuer, subject, intended audience and expiration are also checked.

What are the security advantages over basic authentication?

  • Prevents exposure and replay of the client credential if the client is subjected to a malicious endpoint attack. A JWT created for a malicious token endpoint cannot be replayed with the legitimate authorisation server because of the audience (aud) check.
  • Also prevents exposure of the client credential if for some reason the token request is accidentally sent out via plain HTTP (instead of HTTPS).
  • If the client uses multiple authorisation servers, private_key minimises the number of credentials that need to be stored.

The Connect2id server supports JWT authentication out of the box. However, if you've upgraded from an old server version, make sure JWT auth is indeed configured and so are the JWS crypto algorithms for it.

To register a client for client_secret_jwt authentication with JWS HS256 make a request like this:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"      : "client_secret_jwt",
  "token_endpoint_auth_signing_alg" : "HS256"
}

To register a client for private_key_jwt authentication generate an RSA or EC key pair, and store the private key securely. Export the public key to a JSON Web Key (JWK) set, so that it can be registered with the Connect2id server. To ease key rollover, the JWK should be given a unique key ID (kid) within the set. You can use the Connect2id JWT library to generate and export RSA / EC keys
to the JWK format.

Example registration request for private_key_jwt authentication with JWS RS256:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"      : "private_key_jwt",
  "token_endpoint_auth_signing_alg" : "RS256",
  "jwks"                            : { "keys" : [ { "e" : "AQAB", "n" : "gmlDX_mgMcHX.." ] }
}

If the Connect2id server has a client certificate verifier for private_key_jwt, to enable clients to pass their public key in a qualified certificate put in the JWT's x5c header parameter, there is no need to register a client JWK set.

The registration request is similar, save that there is no jwks or jwks_uri client metadata field now:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"      : "private_key_jwt",
  "token_endpoint_auth_signing_alg" : "RS256" }
}

4.13 How to register a client for mutual TLS authentication and client X.509 certificate bound tokens

The Mutual TLS Profile for OAuth 2.0 enables clients to authenticate with a X.509 certificate and receive access tokens bound to it, enhancing their security over the regular Bearer type.

There are two variants of client certificate authentication:

  • tls_client_auth -- The client certificate is issued by a trusted Certificate Authority (CA).

  • self_signed_tls_client_auth -- The client certificate is self-signed.

To register a client for tls_client_auth set the tls_client_auth_subject_dn metadata parameter to the expected certificate subject distinguished name (DN). Also, make sure tls_client_certificate_bound_access_tokens is set.

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                              : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"                 : "tls_client_auth",
  "tls_client_auth_subject_dn"                 : "cn=appX",
  "tls_client_certificate_bound_access_tokens" : true
}

To register a client for self_signed_tls_client_auth its certificate must be supplied in the client's registration. This is done by putting it inside the x5c (X.509 certificate chain) parameter of a public JWK. Since the certificate is self-signed the x5c array length is exactly one. The JWK type and public key parameters must match those of the included certificate. The JWK itself is supplied within a standard JWK set structure:

  • by value using the jwks parameter, or
  • by URL using the jwks_uri parameter.

Example JWK set with a single RSA key that includes a self-signed RSA certificate:

{
  "keys": [
      {
          "kty" : "RSA",
          "alg" : "RS256",
          "use" : "sig",
          "kid" : "1",
          "n"   : "9HrVGuF7iyoR9oOIu-kISItytKxDLb-BdGmsqx-EBhVI11Q4DhfoxzNyaOWPaPcR6RpPbVAFY-drZgEH4SAQcVUzCUB2DKjLaZaBbCOWu3NYnif2XN0EwMiw4X7XD1qsvzoZbM72ApJ9AcZgPpq9suv8fZoOc__-lhTLTqAK5Ww9j-a_Fh3ADzWYcUfaHXZqQSMfIZTx2b0_X5Uech4ILrFUiEPhpf9zEmF5_Git2UYScwfXb9mW2OjXVVrE8zuI_RH97mSV82QVD_pr2Ikd1LJgB1xYkms5kUlzAm2diw60nqty3KMp_XAUe8fv0vD58Oqe2rNvl-4y8KIBWi8piQ",
          "e"   : "AQAB",
          "x5c": [ "MIICljCCAX6gAwIBAgIGAYgE5hzPMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNVBAMMATEwHhcNMjMwNTEwMDkwMjQ5WhcNMjQwMzA1MDkwMjQ5WjAMMQowCAYDVQQDDAExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9HrVGuF7iyoR9oOIu+kISItytKxDLb+BdGmsqx+EBhVI11Q4DhfoxzNyaOWPaPcR6RpPbVAFY+drZgEH4SAQcVUzCUB2DKjLaZaBbCOWu3NYnif2XN0EwMiw4X7XD1qsvzoZbM72ApJ9AcZgPpq9suv8fZoOc//+lhTLTqAK5Ww9j+a/Fh3ADzWYcUfaHXZqQSMfIZTx2b0/X5Uech4ILrFUiEPhpf9zEmF5/Git2UYScwfXb9mW2OjXVVrE8zuI/RH97mSV82QVD/pr2Ikd1LJgB1xYkms5kUlzAm2diw60nqty3KMp/XAUe8fv0vD58Oqe2rNvl+4y8KIBWi8piQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQC9YQvdqFUfXXOEw0X+z/14RQwAVzTK1cqqtBZJTmUCyXc51jm5hfsN3jnoYEmS888EM55KWF1PlPr0G1P7kvs6sMhhKRJQigxeQmw1YHOIWLRHywI+M0ZLpDcBRLbWtEBPIEuN4DLXM9vnGX/UF05Zgk5/U1oM8Vg1MIfXaIIwshpB3y41vRSJXrdrqxGIwApdCRZX6usYZpiHmbkLWN+0t/jsEggmCoPfOfZKwFTetkAU+hxGE4QJPQ+I/ahhu1XCrejMEAShV2pLFm9VP4ECwjlbQjAqmInE7GhZlerNdwYEbLjr5yOnVLT+XJUPjDdzs/ImDk/8mEQ0qpzSZxTl" ]
      }
  ]
}

The JWK and self-signed client certificate can be generated programmatically.

An example complete registration request:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                              : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"                 : "self_signed_tls_client_auth",
  "jwks"                                       : {
                                                   "keys": [
                                                       {
                                                           "kty" : "RSA",
                                                           "alg" : "RS256",
                                                           "use" : "sig",
                                                           "kid" : "1",
                                                           "n"   : "9HrVGuF7iyoR9oOIu-kISItytKxDLb-BdGmsqx-EBhVI11Q4DhfoxzNyaOWPaPcR6RpPbVAFY-drZgEH4SAQcVUzCUB2DKjLaZaBbCOWu3NYnif2XN0EwMiw4X7XD1qsvzoZbM72ApJ9AcZgPpq9suv8fZoOc__-lhTLTqAK5Ww9j-a_Fh3ADzWYcUfaHXZqQSMfIZTx2b0_X5Uech4ILrFUiEPhpf9zEmF5_Git2UYScwfXb9mW2OjXVVrE8zuI_RH97mSV82QVD_pr2Ikd1LJgB1xYkms5kUlzAm2diw60nqty3KMp_XAUe8fv0vD58Oqe2rNvl-4y8KIBWi8piQ",
                                                           "e"   : "AQAB",
                                                           "x5c": [ "MIICljCCAX6gAwIBAgIGAYgE5hzPMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNVBAMMATEwHhcNMjMwNTEwMDkwMjQ5WhcNMjQwMzA1MDkwMjQ5WjAMMQowCAYDVQQDDAExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9HrVGuF7iyoR9oOIu+kISItytKxDLb+BdGmsqx+EBhVI11Q4DhfoxzNyaOWPaPcR6RpPbVAFY+drZgEH4SAQcVUzCUB2DKjLaZaBbCOWu3NYnif2XN0EwMiw4X7XD1qsvzoZbM72ApJ9AcZgPpq9suv8fZoOc//+lhTLTqAK5Ww9j+a/Fh3ADzWYcUfaHXZqQSMfIZTx2b0/X5Uech4ILrFUiEPhpf9zEmF5/Git2UYScwfXb9mW2OjXVVrE8zuI/RH97mSV82QVD/pr2Ikd1LJgB1xYkms5kUlzAm2diw60nqty3KMp/XAUe8fv0vD58Oqe2rNvl+4y8KIBWi8piQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQC9YQvdqFUfXXOEw0X+z/14RQwAVzTK1cqqtBZJTmUCyXc51jm5hfsN3jnoYEmS888EM55KWF1PlPr0G1P7kvs6sMhhKRJQigxeQmw1YHOIWLRHywI+M0ZLpDcBRLbWtEBPIEuN4DLXM9vnGX/UF05Zgk5/U1oM8Vg1MIfXaIIwshpB3y41vRSJXrdrqxGIwApdCRZX6usYZpiHmbkLWN+0t/jsEggmCoPfOfZKwFTetkAU+hxGE4QJPQ+I/ahhu1XCrejMEAShV2pLFm9VP4ECwjlbQjAqmInE7GhZlerNdwYEbLjr5yOnVLT+XJUPjDdzs/ImDk/8mEQ0qpzSZxTl" ]
                                                       }
                                                   ]
                                                 },
  "tls_client_certificate_bound_access_tokens" : true
}

4.14 How to require Pushed Authorisation Requests (PAR) for a client

A client can be required to use the PAR endpoint by setting the require_pushed_authorization_requests parameter:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                        : [ "https://client.example.org/callback" ],
  "require_pushed_authorization_requests": true
}

This will force upfront authentication of the client (for a confidential client), before involving the end-user with any login and consent related interactions.

4.15 How to register a client for JWT-secured authorisation requests (JAR)

JWT-secured authorisation requests (JAR) (RFC 9101), also called request objects in OpenID Connect, enable signing and optional encryption of the parameters.

Clients that make signed authorisation requests must provide their JWK set, by value (jwks) or by reference (jwks_uri), so that the Connect2id server can validate JWT signatures.

To register a client using public RSA keys for RS256 signed authorisation requests and thus also prevent it from making plain requests:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"      : "private_key_jwt",
  "token_endpoint_auth_signing_alg" : "RS256",
  "jwks_uri"                        : "https://client.example.com/jwks.json",
  "request_object_signing_alg"      : "RS256"
}

If the client is going to be passing the request JWTs by one or more URLs they must be pre-registered in request_uris:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"      : "private_key_jwt",
  "token_endpoint_auth_signing_alg" : "RS256",
  "jwks_uri"                        : "https://client.example.com/jwks.json",
  "request_object_signing_alg"      : "RS256",
  "request_uris"                    : [ "https://client.example.com/requests/a1.jwt",
                                        "https://client.example.com/requests/a2.jwt",
                                        "https://client.example.com/requests/a3.jwt" ]
}

The request JWTs can be additionally set for confidentiality, for example by encrypting them with RSA-OAEP-256 and A128CBC-HS256 to the encryption RSA key published by the Connect2id server:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "token_endpoint_auth_method"      : "private_key_jwt",
  "token_endpoint_auth_signing_alg" : "RS256",
  "jwks_uri"                        : "https://client.example.com/jwks.json",
  "request_object_signing_alg"      : "RS256",
  "request_object_encryption_alg"   : "RSA-OAEP-256",
  "request_object_encryption_enc"   : "A128CBC-HS256"
}

4.16 How to register a client for JWT-secured authorisation responses (JARM)

When a client sets the response_mode authorisation request parameter to jwt the response parameters will be delivered to the callback redirect_uri in a RS256 signed JWT (JARM).

To cause the JWT to be signed with a different JWS algorithm than the default RS256, or, to return all authorisation responses as a JWT, regardless of how the response_mode is set, register the client explicitly for a signing JARM algorithm.

Example registration for a client expecting authorisation responses to be secured with HMAC using the HS256 algorithm:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json`

{
  "redirect_uris"                     : [ "https://client.example.org/callback" ],
  "authorization_signed_response_alg" : "HS256"
}

The JWT responses can be additionally encrypted with JWE, using public key encryption or a shared key derived from the client_secret.

If the client is set up to receive JWT responses encrypted to a public key in the client JWK set, the JWK set must be provided in the registration, either by value or by URL.

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json

{
  "redirect_uris"                        : [ "https://client.example.org/callback" ],
  "jwks_uri"                             : "https://client.example.com/jwks.json",
  "authorization_signed_response_alg"    : "RS256",
  "authorization_encrypted_response_alg" : "RSA-OAEP-256",
  "authorization_encrypted_response_enc" : "A128CBC-HS256"
}

4.17 How to register a client to receive encrypted ID tokens or UserInfo

Example client registration request stating that ID tokens are to be first signed with RSA PKCS #1 and then encrypted with a 128-bit AES key derived from the client secret, using the AES GCM KW algorithm:

POST /clients HTTP/1.1
Host: demo.c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "id_token_signed_response_alg"    : "RS256",
  "id_token_encrypted_response_alg" : "A128GCMKW",
  "id_token_encrypted_response_enc" : "A128CBC-HS256"
}

Registering a client to receive signed and encrypted UserInfo JWTs is similar:

POST /clients HTTP/1.1
Host: demo.c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{
  "redirect_uris"                   : [ "https://client.example.org/callback" ],
  "userinfo_signed_response_alg"    : "RS256",
  "userinfo_encrypted_response_alg" : "A128GCMKW",
  "userinfo_encrypted_response_enc" : "A128CBC-HS256"
}

4.18 How to include additional client data

In case you need to store additional details about a client that don't fit into the standard parameter set the custom data parameter comes to help:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris" : [ "https://myapp.example.com/callback" ],
  "data"          : { "reg_type"  : "3rd-party",
                      "approved"  : true,
                      "author_id" : 792440 }
}

The data parameter permits arbitrary content packaged in a JSON object. To set it you will need the master registration token or a one-time access token with a client-reg:data scope.

4.19 How to register a client with a preset client_id or client_secret

When the Connect2id server registers a new client it generates a random client_id for it. If the chosen client authentication method, ID token JWS algorithm or UserInfo JWS algorithm require it, it also generates a secret of the appropriate length.

This is the standard behaviour and fine for most situations. You may however want to preset the client identifier and / or secret to a specific value, if migrating existing clients to the Connect2id server for example.

To do that make a registration request with the master API access token using the following non-standard parameters to specify the desired values:

  • preferred_client_id to preset the client identifier
  • preferred_client_secret to preset the client secret (also works when updating an existing client registration).

For example, to register a client with a preset client_id and client_secret for the password grant:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types"             : [ "password" ],
  "preferred_client_id"     : "123456",
  "preferred_client_secret" : "ahL7AhthchiNg6beAo5HeijeThae3deiChab7ajiVuip2eodesoBie0ufohtiiK4"
}

The server will then register the client under the preferred identifier and secret, provided there's no collision with an existing client and the secret is not too short.

In case the client_id is already taken you will get a standard invalid_client_metadata error:

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
 "error"             : "invalid_client_metadata",
 "error_description" : "Invalid client metadata field: The preferred client_id is already in use"
}

In case the secret is too short for the chosen client authentication method, ID token JWS algorithm or UserInfo JWS algorithm, the Connect2id server will return the following error:

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
 "error"             : "invalid_client_metadata",
 "error_description" : "Invalid client metadata field: The preferred secret must be at least 256 bits"
}

The preset client secret facility can also be used to import hashed or otherwise encoded client secrets from another server:

POST /clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "grant_types"             : [ "password" ],
  "preferred_client_id"     : "123456",
  "preferred_client_secret" : "$2a$04$a9uQ9Ka0usxqTCp/1je2iuS.qnVsXKe0Gjhh5kPEhnbInkseODhgS"
}

5. References

Client registration is defined in three specs:

6. Frequently asked questions (FAQ)

6.1 Why is the client authentication method locked down at registration time?

The token_endpoint_auth_method is locked down at registration time intentionally, to prevent accidental or intentional downgrades. Mostly to prevent a client registered for JWT authentication to use the less safe basic method.

6.2 Can I register a client for multiple grants / response types?

You may, however this complicates the management of the client account, and may also lead to unwanted side effects. For example, a client registered for the code as well as the implicit grants may not be issued a refresh token, or may have its refresh token invalidated.

We recommend that you always register a client for a single grant / flow only.

If a client needs to make use of more than one grant / flow, register a separate client identity (client_id) for each one.