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 or EC public signing key or keys; Uber stores them 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/v2/oauth/register |
¶ 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
- One or more RSA-2048 (or stronger) or EC P-256 key pairs. The JWKS you provide must contain the public key or keys. You retain each private key and use it to sign client assertions when calling the token endpoint as the newly-registered client.
¶ Generate a JWKS
Generate one or more key pairs locally. Send the public half as a JWKS object in the jwks field of the registration request. Keep each private half securely; you’ll use it later to sign client assertions when calling the token endpoint as the registered client.
Uber supports JWKS rotation during registration. You may include one or more signing keys in the keys array. Uber registers every usable RSA signing key (kty: "RSA") and EC P-256 signing key (kty: "EC", crv: "P-256") whose use is omitted or set to sig; keys with use set to enc are not registered for token endpoint authentication.
Provide a kid for each key you plan to use. The kid must be a UUID string and must match the kid JWT header you send later in the client_assertion. Unsupported key types or EC curves are ignored; registration requires at least one usable signing key.
| Key type | Public JWK fields to include | JWT signing algorithm |
|---|---|---|
| RSA | kty, kid, n, e |
RS256 |
| EC P-256 | kty, kid, crv, x, y |
ES256 |
The language snippets below generate an RSA JWKS. For EC P-256, generate an EC key pair and send a public JWK with kty: "EC", crv: "P-256", and base64url-encoded x and y coordinates. Set alg to ES256 for EC P-256 keys and RS256 for RSA keys so the JWKS documents the signing algorithm your token requests will use.
¶ 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 JSON to send to Uber and the private key
// to retain locally for signing client assertions. The kid value must be
// sent later as the client_assertion JWT kid header.
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 object 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/v2/oauth/register - 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 |
object | Yes | JSON Web Key Set containing one or more RSA or EC P-256 public signing keys used for private_key_jwt authentication. Use RSA-2048 or stronger keys for RS256, or EC P-256 keys for ES256. Each kid must be a UUID and must match the JWT kid header used later. |
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/v2/oauth/register' \
-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": "4d00ebc0-3b70-4f85-b873-8bcfbf1567f6",
"n": "<base64url-encoded-modulus>",
"e": "AQAB"
},
{
"kty": "EC",
"use": "sig",
"alg": "ES256",
"kid": "a1daed88-cf91-4f66-9a10-6a234f5e82c5",
"crv": "P-256",
"x": "<base64url-encoded-x-coordinate>",
"y": "<base64url-encoded-y-coordinate>"
}
]
},
"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 |
|---|---|---|
clientId |
string | Unique identifier for the newly registered application |
scope |
string | Space-delimited list of scopes granted to the client |
tokenEndpointAuthMethod |
string | Always private_key_jwt — authenticate token requests by signing a JWT with the RSA or EC private key matching a registered JWKS kid |
webhookSigningSecret |
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:
{
"clientId": "abc123xyz",
"scope": "profile",
"tokenEndpointAuthMethod": "private_key_jwt",
"webhookSigningSecret": "a3f8c2...d9e1"
}
¶ Webhook Verification
If you registered a webhook_uri, Uber signs each webhook payload using the webhookSigningSecret returned at registration. Verify the signature to confirm the payload is authentic:
- Extract the
X-Uber-Signatureheader from the incoming request. - Compute
HMAC-SHA256(webhookSigningSecret, 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 or contains no usable RSA or EC P-256 signing key |
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 with the RSA or EC private key that matches one of your registered JWKS kid values, see Client Asymmetric Key Authentication.