How to register an OAuth 2.0 / OpenID Connect client

1. Why sign up clients?

A client must be signed up with the Connect2id server before it can request OpenID Connect or OAuth 2.0 tokens from it.

First and foremost this establishes the credentials for identifying and authenticating the client in the requests that will follow. Second, this sets up various global client settings, such as the preferred crypto algorithm for the ID tokens that will be issued to the client. Without these settings there won't be enough context to complete many of the client requests, as the OAuth requests are designed to be fairly minimal and carry few parameters.

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

  • The methods, or grant types in OAuth jargon, that the client will use to obtain the end-user's authorisation and tokens. Depending on the grant, additional parameters may be required, such as a callback URL.

  • The preferred security algorithms for the client authentication, the ID tokens and other objects exchanged between client and server, unless the client wants to stick with the default ones (such as HTTP basic auth and RS256 for 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 details are not mandatory, but quite essential for a good user experience.

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

For each successfully registered client the Connect2id server will provision the following:

  • A unique client ID;

  • A client secret (or password). It is used to authenticate client requests to the server, and must therefore be securely stored and not shared with third parties. Note that a client may register its own JSON Web Key (JWK) material, such as an RSA key, and opt out of the default HTTP basic authentication. In that case a shared secret is not required and will not be provisioned;

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

2. The client registration endpoint

Clients are registered at a RESTful endpoint advertised in the Connect2id server metadata. Its URL looks like this:

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

3. Controlling access to the registration endpoint

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

Even with enabled open registration, an access token is still required to sign up a client for certain OAuth 2.0 grant types (such as password or client_credentials), or to set the scope registration parameter.

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

Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

If you fail to pass an access token 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 sign up a few example clients with the demo Connect2id server, which permits open registration and has its client registration endpoint at

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

4.1 Minimal registration

To sign up 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 /c2id/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/c2id/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 mentioned in the beginning, the server will provision the following important parameters for your client, which must be kept safe:

  • The client_id and client_secret credentials to authenticate the client in future login and token requests.

  • The registration URI and access token to read, modify or delete the client registration later, in a RESTful manner.

Some 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.

  • 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) using the RS256 algorithm.

The other parameters matter less; you can read about them in the OpenID Connect spec.

The response will also confirm the registered callback URL. Note that you may register more than one if that's required by your app.

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/c2id/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 some part of the request is invalid or malformed, you will get a 400 Bad Request error:

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 Specifying client app details for display to end-users

When browsers get redirected to the Connect2id server to sign-in an end-user it's nice to be able to display the application's name, logo and other helpful information.

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 sign up another client, and provide its name, logo and other details:

POST /c2id/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/c2id/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.3 How to register a public OAuth 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 also also available).

In order to register a public client, first make sure the Connect2id server is configured to permit that, by including none in the list of the supported client authentication method.

Then, to perform the actual registration of a public client, set the request parameter for the token endpoint authentication method to none.

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

POST /c2id/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"
}

Note that the app type must be explicitly set to native to permit registration of a custom redirection URI such as the above!

Example registration request for a public web client (JavaScript app using the implicit flow and a custom redirection URI):

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

{
  "grant_types"                : [ "implicit" ],
  "response_types"             : [ "token id_token", "id_token" ],
  "redirect_uris"              : [ "https://myapp.example.com/?callback" ],
  "token_endpoint_auth_method" : "none"
}

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

If the sign up 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 sign up 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/c2id/.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 /c2id/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.5 How to register a client for the password grant

Use of the password grant carries higher security risks and therefore to sign up for it must always be pre-authorised. This can be the configured master access token for the client registration endpoint, or a specially provisioned one-time access token.

Minimal sign up request for the password grant:

POST /c2id/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 /c2id/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.6 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 case (on behalf of an end-user).

An initial registration token is also always required here.

POST /c2id/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 may be required by the grant handler, e.g. to bound the scope values that the client is authorised to use:

POST /c2id/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"
}

4.7 How to register a grant-less client

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

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

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

4.8 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 the most 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, and carries the following parameters in its payload:

  • iss The token issuer, which is represented by the client_id.
  • sub The token subject, which is again set to the client_id.
  • aud The token audience, set to the URL of the token endpoint.
  • exp The token expiration.

Example JWT payload:

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

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 a SHA256-based HMAC make a request like this:

POST /c2id/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 using RSA signatures with SHA256:

POST /c2id/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.." ] }
}

4.9 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.

The client X.509 certificate can be self-signed, which does away with the need to maintain a CA and PKIX. In that case, however, the certificate public key (RSA or EC, in JWK format) must be registered with the Connect2id server.

The JWK and self-signed client certificate can be generated programmatically or using a command line utility.

When registering the client, set the token endpoint authentication method to self_signed_tls_client_auth and supply the public JWK for the client certificate:

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

Also, make sure mutual_tls_sender_constrained_access_tokens is set.

POST /c2id/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" : [ { "e" : "AQAB", "n" : "gmlDX_mgMcHX.." } ] },
  "mutual_tls_sender_constrained_access_tokens" : true
}

4.10 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"
}

The Connect2id server supports all standard JWE algorithms for symmetric and public key encryption.

4.11 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 /c2id/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.12 How to register a client with a preset client_id and / 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 /c2id/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"
}

This feature has been added in Connect2id server version 2.2 (2.5 for the preferred client secret).

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.