# Common IAM Guide

Integration with Sportradar services typically involves **machine-to-machine (M2M) communication**. To access these services, **external consumers (machines)** must authenticate through **Sportradar Common IAM**, which is built on top of [**Auth0 Identity Provider**](https://auth0.com/).

Sportradar follows **industry-standard security practices** and uses **OAuth 2.0** for authentication and **OpenID Connect (OIDC)** for identity management. These protocols securely authenticate both **machine and human users** and ensure safe, controlled access to Sportradar services.

### Environments

**Sportradar Common IAM** provides two environments for external customers:

* **Production environment domain:** [`https://auth.sportradar.com`](https://auth.sportradar.com/)
* **Staging environment domain:** [`https://stg-auth.sportradar.com`](https://stg-auth.sportradar.com/)

Use these environments separately for integration and testing. The **staging environment** is recommended for development and pre-production testing.

### Service account

In Sportradar, a **Service Account** refers to a **machine user**. It is an identity intended for programmatic, machine-to-machine authentication. A Service Account is used for **M2M applications** such as **command-line tools (CLIs)**, **daemons**, or **backend services** that operate **without user interaction** and need to authenticate securely with APIs.

Sportradar supports two authentication methods for **M2M authentication**:

1. **Client ID and Client Secret** — a standard OAuth 2.0 flow where the machine authenticates using a shared secret.
2. **Private Key JWT (JSON Web Token)** — a more secure method that uses asymmetric encryption. The machine authenticates using a signed JWT and a private key. It also enables **easier credential rotation** through a private/public key pair.

Both methods follow the **OAuth 2.0 Client Credentials Grant Flow**, as illustrated below. While the implementations differ, the resulting `access_token` uses the **same format** in both cases.

<figure><img src="/files/ZWKQkDvb1d3zAtpnkHB6" alt=""><figcaption></figcaption></figure>

#### Client ID and Client Secret authentication

Your Sportradar contact will configure a Service Account for you and securely share the **Client ID**, **Client Secret**, and **API audience identifier** through **Sportradar-approved secure communication channels**, such as [**Keeper**](https://www.keepersecurity.com/).

**Self-management**

Currently, there is **no unified self-service interface** for fully managing **Service Accounts** independently. You need to coordinate with your **Sportradar contact** to complete the configuration process.

In the future, a **self-service mechanism** is planned. It will let you manage **Service Accounts**, including secret operations, **without manual intervention from Sportradar**.

To authenticate a **Service Account** with **Common IAM**, follow these steps.

**1. Client initiates the token request**

Send a POST request to the Common IAM `https://<COMMON-IAM-DOMAIN>/oauth/token` endpoint with the required parameters.

**HTTP request example**

```bash
curl --request POST 'https://<COMMON-IAM-DOMAIN>/oauth/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'client_id=SERVICE_ACCOUNT_ID' \
  --data-urlencode 'client_secret=SERVICE_ACCOUNT_SECRET' \
  --data-urlencode 'audience=API_IDENTIFIER'
```

**Parameters**

* `client_id`: Service Account ID
* `client_secret`: Service Account secret
* `audience`: Identifier of the API the client wants to access
* `grant_type`: Must be `client_credentials`
* `<COMMON-IAM-DOMAIN>`: The Common IAM environment domain, for example:
  * **Staging:** [`stg-auth.sportradar.com`](http://stg-auth.sportradar.com/)
  * **Production:** [`auth.sportradar.com`](http://auth.sportradar.com/)

**2. Receive the access token**

If the request is valid, the response includes an **access token**, its type (`Bearer`), and its expiration time in seconds.

**HTTP response example**

```json
{
  "access_token": "YOUR_ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

**3. Store and reuse the access token for subsequent API requests**

Include the issued `access_token` in the `Authorization` header as a **Bearer token** when making HTTP requests to Sportradar APIs.

**Access token usage**

```bash
curl -H "Authorization: Bearer eyJhbGciOi..." https://api.example.com/data
```

**Important**

To avoid unnecessary HTTP calls, reduce load on the identity provider, and prevent rate-limit issues, the access token should be:

* **Stored in memory** within the application
* **Reused** for subsequent API requests until it expires

**Recommended approach:** Use an **in-memory cache** to store and automatically refresh the token just before, or when, it expires.

**Access token format**

```json
{
  "https://sportradar/common-iam/accounts": [
    "{account_id associated with the provided credentials - this is usually the customer account ID in Sportradar}"
  ],
  "iss": "https://{COMMON-IAM-DOMAIN}",
  "sub": "{clientid}@clients",
  "aud": "{api_identifier_to_which_this_token_was_issued}",
  "iat": 1692866363,
  "exp": 1692866663,
  "azp": "{clientid}",
  "gty": "client-credentials"
}
```

#### Private Key JWT authentication

When using **Private Key JWT authentication**, you are responsible for generating a valid **private/public key pair** for authentication. You must securely share your **public key** with your Sportradar contact. They will configure the associated **Service Account** and register the public key for you. Your Sportradar contact will also share the **API audience identifier** and other required Service Account details.

**Self-management**

Currently, there is **no unified self-service interface** for fully managing **Service Accounts** independently. You need to coordinate with your **Sportradar contact** to complete the configuration process.

In the future, a **self-service mechanism** is planned. It will let you manage **Service Accounts**, including public key operations, **without manual intervention from Sportradar**.

This approach improves security by using asymmetric key pairs and avoids storing client secrets.

The authentication flow is illustrated below.

<figure><img src="/files/nqB9Rqf0abFUDje5gC3X" alt=""><figcaption></figcaption></figure>

![](https://confluence.sportradar.ag/download/attachments/1392222041/image-2024-11-14_12-8-49.png?version=1\&modificationDate=1744893838000\&api=v2)

More details are available in [Authenticate with Private Key JWT](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authenticate-with-private-key-jwt).

To authenticate a **Service Account** using **Private Key JWT** with **Common IAM**, follow these steps.

**1. Generate an RSA key pair**

Before your Sportradar contact configures a Service Account for authentication, you must first **generate an RSA private/public key pair**.

The **public key** must use the **RS256, RS384, or PS256** algorithm, be encoded in **PEM format**, and be shared with your **Sportradar contact person**. The Sportradar contact person needs the following parameters when configuring the public key in Common IAM.

|                              |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                       | Name of the public key.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `algorithm`                  | Algorithm used to sign assertions. Supported values are **RS256**, **RS384**, and **PS256**. If not specified, the default algorithm is **RS256**.                                                                                                                                                                                                                                                                                                                                                                                     |
| `pem`                        | Public key, or X.509 certificate, encoded in **PEM format**.                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| <sub>`expiration date`</sub> | <p><strong>Optional</strong>:</p><p>When uploading a public key or certificate for a Service Account in Common IAM, you can define an expiration date. If no expiration is specified, the certificate is treated as non-expiring.</p><p>It is possible to choose from the following options:</p><ol><li>Never — the public key does not expire.</li><li>Specific Date — manually set a custom expiration date.</li><li>Date from Public Key — automatically extract and use the expiration date embedded in the certificate.</li></ol> |

* **Minimum key size:** 2048 bits
* **Maximum key size:** 4096 bits
* **Recommended:** Generate a 2048-bit key with OpenSSL

**Example OpenSSL command**

```bash
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -in private_key.pem -pubout -out public_key.pem
```

Once generated:

* Keep the **private key** secure. It is used to sign JWTs.
* Share the **public key** with your Sportradar contact to configure your Service Account.

**2. Build the JWT assertion**

The assertion is a JSON Web Token (JWT). It is a **one-time-use token**, so it should have a short expiry. We recommend a maximum lifetime of **1 minute**.

You can:

* Use an **Auth0 SDK** to build the JWT automatically
* Construct it manually if you use a custom implementation

The JWT should contain the following properties and claims.

* **Header**
  * `alg`: The algorithm used to sign the assertion. It must match the **algorithm specified when generating the private/public key pair**.
  * `kid` (optional): The Common IAM (Auth0) generated `kid` for the public key. This `kid` is **generated when the public key is added in Common IAM** and must be shared with you by your Sportradar contact person.
* **Payload**
  * `iss`: Service Account ID. This is the **Common IAM (Auth0) generated ID** and must be shared with you by your Sportradar contact person.
  * `sub`: Service Account ID. This is the **Common IAM (Auth0) generated ID** and must be shared with you by your Sportradar contact person.
  * `aud`: The URL of the Auth0 tenant, which is the **Common IAM domain**, including the trailing slash. For example, <https://stg-auth.sportradar.com/>
  * `iat` (optional) and `exp`: Issued At and Expiration claims set to the correct **timestamps**. The client assertion is a one-time-use token, and the shortest possible expiry time is recommended. Auth0 supports a maximum token lifetime of **5 minutes**.
  * `jti`: A **unique claim ID** created by you. We recommend using the **UUID** format.

The token **must be signed with the private key generated in the first step**. The maximum length of the JWT assertion is **2048 bytes**.

More details are available in [Authenticate with Private Key JWT](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authenticate-with-private-key-jwt).

**JWT best practices**

* Use a short expiry time. We recommend **1 minute**.
* **Maximum lifetime:** 5 minutes
* **Maximum size:** 2048 bytes

**JWT structure**

**Header**

```json
{
  "alg": "RS256",
  "kid": "optional-key-id"
}
```

**Payload**

```json
{
  "iss": "SERVICE_ACCOUNT_ID",
  "sub": "SERVICE_ACCOUNT_ID",
  "aud": "https://stg-auth.sportradar.com/",
  "iat": 1710000000,
  "exp": 1710000060,
  "jti": "unique-uuid-string"
}
```

**Recommendation**

We recommend generating the `jti` with a UUID.

**JWT field constraints**

|       |               |
| ----- | ------------- |
| `iss` | 64 characters |
| `sub` | 64 characters |
| `jti` | 64 characters |
| `alg` | 16 characters |

**3. Exchange the JWT for an access token**

Once the JWT assertion is created and signed with your private key, you can exchange it for an **access token** by calling the Common IAM token endpoint. Send a POST request to `https://<COMMON-IAM-DOMAIN>/oauth/token` with the required parameters.

**HTTP request example**

```bash
curl --location --request POST 'https://<COMMON-IAM-DOMAIN>/oauth/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
  --data-urlencode 'client_assertion=<your_signed_jwt>' \
  --data-urlencode 'audience=<api_identifier>'
```

**Parameters**

* `client_assertion`: The JWT signed with your private key
* `client_assertion_type`: Always use `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`
* `audience`: The **API identifier** for the API you are accessing
* `<COMMON-IAM-DOMAIN>`: The Common IAM environment domain, for example:
  * **Staging:** [`stg-auth.sportradar.com`](http://stg-auth.sportradar.com/)
  * **Production:** [`auth.sportradar.com`](http://auth.sportradar.com/)

**4. Receive the access token**

If the request is valid, the response includes an **access token**, its type (`Bearer`), and its expiration time in seconds.

**HTTP response example**

```json
{
  "access_token": "YOUR_ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

**5. Store and reuse the access token for subsequent API requests**

Include the issued `access_token` in the `Authorization` header as a **Bearer token** when making HTTP requests to Sportradar APIs.

**Access token usage**

```bash
curl -H "Authorization: Bearer eyJhbGciOi..." https://api.example.com/data
```

**Important**

To avoid unnecessary HTTP calls, reduce load on the identity provider, and prevent rate-limit issues, the access token should be:

* **Stored in memory** within the application
* **Reused** for subsequent API requests until it expires

**Recommended approach:** Use an **in-memory cache** to store and automatically refresh the token just before, or when, it expires.

**Access token format**

```json
{
  "https://sportradar/common-iam/accounts": [
    "{account_id associated with the provided credentials - this is usually the customer account ID in Sportradar}"
  ],
  "iss": "https://{COMMON-IAM-DOMAIN}",
  "sub": "{clientid}@clients",
  "aud": "{api_identifier_to_which_this_token_was_issued}",
  "iat": 1692866363,
  "exp": 1692866663,
  "azp": "{clientid}",
  "gty": "client-credentials"
}
```

### Best practices for implementing the Client Credentials Flow

#### Token expiration and renewal

Access tokens issued through the **Client Credentials Flow** have a limited lifespan. To maintain secure and uninterrupted communication, track the token’s expiration time and renew it before it expires.

Your application should:

* Monitor the `expires_in` field returned with the token
* Automatically trigger a new Client Credentials Flow request **before the token expires**
* Handle renewal seamlessly within the application runtime

**Tip**

Implement renewal logic that avoids simultaneous token re-requests from multiple threads or services whenever possible.

#### In-application token caching

Using in-application caching is an effective way to:

* Reduce unnecessary token requests to the identity provider
* Improve the performance and reliability of API calls

The recommended approach is to implement a **lightweight in-memory cache** within your M2M application that:

* Stores the access token temporarily
* Validates whether the token is still valid, for example by checking its expiration timestamp
* Requests a new token **only when the current one has expired**

Ensure your caching mechanism is thread-safe and supports concurrent requests in multithreaded environments.

#### Optimization recommendation provided by the identity provider

An Okta document describes an additional solution for improving access-token handling in M2M communication. It is provided as a separate document. Check with your Sportradar contact person if you have not received it.

[![](https://confluence.sportradar.ag/rest/documentConversion/latest/conversion/thumbnail/1102766876/1)](https://confluence.sportradar.ag/download/attachments/679238053/Optimizing%20External%20M2M%20Token%20Reuse.pdf?version=1\&modificationDate=1727446820000\&api=v2) PDF

### Secret or key rotation

To enhance security and align with **Sportradar security policies**, rotate secrets and keys periodically. Ideally, do this **quarterly**, but at minimum **once per year**.

Not rotating secrets or keys does **not immediately break existing integrations**. However, your **Sportradar contact may request rotation** as part of regular security practices or audits.

**Self-management**

Currently, there is **no unified self-service interface** for rotating secrets or keys independently. You need to involve your **Sportradar contact person** to complete the rotation process.

In the future, a **self-service mechanism** is planned. It will let you rotate secrets or keys **without involving Sportradar**.

The rotation process differs for **secrets** used in **Client ID and Client Secret authentication** and **keys** used in **Private Key JWT authentication**.

#### Secret rotation (Client ID and Client Secret authentication)

**Common IAM supports only one active client secret per Service Account at a time.** However, you can still perform secret rotation **without downtime** by following the procedure below.

**Prerequisites**

Your system must be able to manage either:

* A **list of client secrets**
* Two separate configuration entries:
  * `CURRENT` — the active secret
  * `NEXT` — the new secret to use during rotation

By default, the system uses the `CURRENT` secret. If a client authentication error occurs during token exchange and indicates an issue with the client credentials, your system should be able to:

* **Retry the operation using the `NEXT` secret** or the next secret in the list
* If the retry succeeds, **promote `NEXT` to `CURRENT`** and discard the old secret

**Secret rotation steps**

1. **Generate the new secret**\
   A **Sportradar contact** generates a new client secret in **Common IAM** for your application.
   * This secret is **not yet active** in Auth0.
   * The Sportradar contact shares the new secret with you.
   * You configure the new secret in your system as `NEXT` and inform your Sportradar contact.
2. **Activate the secret in Auth0**\
   The Sportradar contact sets the **new secret as the active default** in Auth0 for your Service Account.

**How zero-downtime rotation works**

If your system is configured to **fall back automatically to the `NEXT` secret**:

* Once the new secret becomes active in Auth0, your system switches to it seamlessly.
* If an API request fails because of an invalid client secret, your system retries with `NEXT`.
* If the retry succeeds, your system promotes `NEXT` to `CURRENT` and discards the old secret.

This process ensures **zero downtime** and avoids manual intervention during secret rotation.

#### Private/public key pair rotation (Private Key JWT authentication)

**Common IAM supports up to two active public keys per Service Account at the same time.** This enables **zero-downtime key rotation** when you follow the steps below.

**Option 1 — Single key configuration**

If you prefer not to use the `CURRENT` and `NEXT` key approach from Option 2, you can maintain a single key in your configuration. Once your Sportradar contact confirms that the new public key is active in Common IAM for your Service Account, you can replace the old key with the new one in your system.

**Prerequisites**

* You must generate a new **private/public key pair**

**Key rotation steps**

**1. Generate a new key pair**

* Create a new **RSA private/public key pair** as described earlier.
* At this point, the new public key is **not yet active in Common IAM**.
* Share the **new public key** with your **Sportradar contact**.

**2. Activate the public key in Common IAM**

* The **Sportradar contact** adds and activates the new public key for your Service Account in Common IAM.
* The **Sportradar contact informs you** when the configuration is complete.
* At this point, you have **two active public keys in Common IAM**, and both can sign JWT assertions.

**3. Switch to the new key**

* **Replace the old private key** with the new one in your configuration.
* **Inform your Sportradar contact** that the old public key can be removed from Common IAM.

**Option 2 — CURRENT and NEXT keys configuration**

**Prerequisites**

* You must generate a new **private/public key pair**
* By default, your system uses the `CURRENT` private key to sign JWT assertions
* If a client authentication error occurs during token exchange and is related to client credentials, your system should be able to:
  * Retry the operation using the `NEXT` key
  * If the retry succeeds, **promote `NEXT` to `CURRENT`** and **discard the old key**

**Key rotation steps**

**1. Generate a new key pair**

* Create a new **RSA private/public key pair** as described earlier.
* At this point, the new public key is **not yet active in Common IAM**.
* Share the **new public key** with your **Sportradar contact**.
* Store the **private key** securely in your system as the `NEXT` key.

**2. Activate the public key in Common IAM**

* The **Sportradar contact** **adds and activates the new public key** for your Service Account in Common IAM.
* The **Sportradar contact** **deactivates and removes** the old public key from Common IAM.
* The **Sportradar contact informs you** when the configuration is complete.

**3. Switch to the new key**

* Your system **begins signing JWT assertions with the new private key through the fallback mechanism**.
* Your system **removes the old key pair** from its configuration by promoting the `NEXT` private key to `CURRENT`.

**How zero-downtime key rotation works**

This approach ensures a **seamless transition with no downtime**:

* While both keys are active in Common IAM, your system can either replace the current private key directly in **Option 1 — Single key configuration**, or fall back to the `NEXT` key if the `CURRENT` key is rejected in **Option 2 — CURRENT and NEXT keys configuration**
* After successful authentication with the new key, the old key is safely retired

This method avoids service disruptions and minimizes the need for manual intervention.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sportradar.com/live-data/live-data-golf-api-design/ld-golf-api-documentation/common-iam-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
