Dynamic Client Registration
¶ Overview
Dynamic Client Registration (DCR) lets your backend programmatically register a new OAuth application with Uber without using the Developer Dashboard. This is useful when you need to create client credentials on behalf of multiple sub-organizations or partners at scale.
The registered client uses private_key_jwt for token endpoint authentication. You provide a JSON Web Key Set (JWKS) containing your RSA public key; Uber stores it and validates your signed client assertions during token requests.
OAuth 2.0 endpoints
| Authorization Host | https://auth.uber.com |
| Token Endpoint | https://auth.uber.com/oauth/v2/token |
| DCR Endpoint | https://api.uber.com/oauth/v2/clients |
¶ Required Scopes
Two scopes grant access to the DCR endpoint, depending on your integration type:
| Scope | Grant Type | When to use |
|---|---|---|
oauth.dcr |
Authorization Code | Your end user (organization admin) authorizes the registration via an OAuth consent flow |
oauth.dcr.b2b |
Client Credentials | Your backend registers clients server-to-server without a user present |
Contact your Uber Partner Engineer to request one of these scopes for your application.
¶ Prerequisites
- A Developer account and application registered at developer.uber.com
- An RSA-2048 (or stronger) key pair. The JWKS you provide must contain the public key. You retain the private key and use it to sign client assertions when calling the token endpoint as the newly-registered client.
¶ Generate a JWKS
Generate an RSA-2048 key pair locally. Send the public half as a JWKS in the jwks field of the registration request. Keep the private half securely; you’ll use it later to sign client assertions when calling the token endpoint as the registered client.
¶ Golang
expand to see code snippets
import (
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"encoding/json"
"math/big"
"github.com/google/uuid"
)
type jwk struct {
Kty string `json:"kty"`
Use string `json:"use"`
Alg string `json:"alg"`
Kid string `json:"kid"`
N string `json:"n"`
E string `json:"e"`
}
type jwks struct {
Keys []jwk `json:"keys"`
}
// GenerateJWKS returns the JWKS string to send to Uber and the private key
// to retain locally for signing client assertions.
func GenerateJWKS() (string, *rsa.PrivateKey, error) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return "", nil, err
}
pub := priv.PublicKey
set := jwks{Keys: []jwk{{
Kty: "RSA",
Use: "sig",
Alg: "RS256",
Kid: uuid.New().String(),
N: base64.RawURLEncoding.EncodeToString(pub.N.Bytes()),
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(pub.E)).Bytes()),
}}}
b, err := json.Marshal(set)
if err != nil {
return "", nil, err
}
return string(b), priv, nil
}
¶ Java
expand to see code snippets
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
public class JWKSGenerator {
// Returns the JWKS JSON to send to Uber. Persist the KeyPair's private key
// locally for signing client assertions later.
public static String generateJWKS(KeyPair[] outKeyPair) throws Exception {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048);
KeyPair kp = gen.generateKeyPair();
outKeyPair[0] = kp;
RSAKey publicJwk = new RSAKey.Builder((RSAPublicKey) kp.getPublic())
.keyUse(KeyUse.SIGNATURE)
.algorithm(JWSAlgorithm.RS256)
.keyID(UUID.randomUUID().toString())
.build()
.toPublicJWK();
return new JWKSet(publicJwk).toString();
}
}
¶ Python
expand to see code snippets
import json
import uuid
from jwcrypto import jwk
def generate_jwks():
# Generate an RSA-2048 key as a JWK
key = jwk.JWK.generate(
kty="RSA",
size=2048,
kid=str(uuid.uuid4()),
use="sig",
alg="RS256",
)
# Public-only JWKS for the DCR request body
public_jwks = {"keys": [json.loads(key.export(private_key=False))]}
# Private key (PEM) to retain locally for client_assertion signing
private_pem = key.export_to_pem(private_key=True, password=None)
return json.dumps(public_jwks), private_pem
¶ Obtain an Access Token
Acquire an access token carrying either the oauth.dcr or oauth.dcr.b2b scope before calling the DCR endpoint:
oauth.dcr— use the Authorization Code Flow.oauth.dcr.b2b— use the Client Credentials Flow.
Pass the resulting token in the Authorization: Bearer <access_token> header on all requests below.
¶ Register a Client
Call the DCR endpoint with the access token obtained above. The request body is JSON.
Request Details:
- Method:
POST - URL:
https://api.uber.com/oauth/v2/clients - Content-Type:
application/json - Authorization:
Bearer <access_token>
Request Body Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
client_name |
string | Yes | Display name for the new application |
client_description |
string | No | Short description of the application |
redirect_uris |
array of strings | Yes (for auth-code clients) | Allowed redirect URIs for the OAuth consent flow |
jwks |
string (JSON) | Yes | JSON Web Key Set containing the RSA public key used for private_key_jwt authentication. Minimum 2048-bit modulus. |
scope |
string | No | Space-delimited list of OAuth scopes to request. Defaults to all scopes approved for your integration if omitted. |
privacy_policy_uri |
string | No | URL to the application’s privacy policy |
webhook_uri |
string | No | HTTPS endpoint to receive Uber webhook events for this client |
contacts |
array of strings | No | Developer email addresses to invite as collaborators on the registered application |
organization_uuid |
string | Yes | UUID of the organization this client belongs to |
Example Request:
curl -X POST 'https://api.uber.com/oauth/v2/clients' \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"client_name": "Ramen XYZ Payment Integration",
"client_description": "Payment integration for Ramen XYZ partner stores",
"redirect_uris": ["https://ramen-xyz.com/auth/callback"],
"jwks": "{\"keys\":[{\"kty\":\"RSA\",\"use\":\"sig\",\"alg\":\"RS256\",\"kid\":\"my-key-1\",\"n\":\"<modulus>\",\"e\":\"AQAB\"}]}",
"scope": "profile",
"privacy_policy_uri": "https://ramen-xyz.com/privacy",
"webhook_uri": "https://ramen-xyz.com/webhooks/uber",
"contacts": ["dev@ramen-xyz.com"],
"organization_uuid": "<YOUR_ORGANIZATION_UUID>"
}'
Response Parameters:
| Field | Type | Description |
|---|---|---|
client_id |
string | Unique identifier for the newly registered application |
scope |
string | Space-delimited list of scopes granted to the client |
token_endpoint_auth_method |
string | Always private_key_jwt — authenticate token requests by signing a JWT with your RSA private key |
webhook_signing_secret |
string | Present only when webhook_uri was provided. HMAC-SHA256 secret used to verify Uber webhook payloads. Store this securely; it will not be returned again. |
Example Response:
{
"client_id": "abc123xyz",
"scope": "profile",
"token_endpoint_auth_method": "private_key_jwt",
"webhook_signing_secret": "a3f8c2...d9e1"
}
¶ Webhook Verification
If you registered a webhook_uri, Uber signs each webhook payload using the webhook_signing_secret returned at registration. Verify the signature to confirm the payload is authentic:
- Extract the
X-Uber-Signatureheader from the incoming request. - Compute
HMAC-SHA256(webhook_signing_secret, request_body). - Compare your computed value with the header value. Reject the request if they do not match.
¶ Error Handling
| HTTP Status | Error | Description |
|---|---|---|
400 |
invalid_request |
Required parameter missing or malformed |
400 |
invalid_redirect_uri |
One or more redirect_uris are invalid or disallowed |
400 |
invalid_jwks |
The jwks field could not be parsed, contains no usable RSA signing key, or the key is below the minimum required size (2048 bits) |
401 |
unauthorized |
Missing or invalid access token |
403 |
forbidden |
Access token does not carry the required oauth.dcr or oauth.dcr.b2b scope |
429 |
too_many_requests |
Rate limit exceeded. Back off and retry. |
500 |
server_error |
Unexpected server error |
¶ Next Steps
The registered client authenticates to Uber’s token endpoint using private_key_jwt. For details on building and signing the client_assertion JWT and exchanging it for an access token, see Client Asymmetric Key Authentication.