> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.rabot.energy/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth Authentication & Scopes

> Learn how to Authenticate your Client using the right Scopes to access our API 

The RABOT Partner API uses OAuth 2.0 for authentication (see [RFC 7649](https://www.rfc-editor.org/rfc/rfc6749)). Using the OAuth *client credentials flow*, you can obtain an access token from the RABOT authentication server.

### Available Environments

For development and testing purposes, the API is also available in a **test environment**, where you can create and modify data without triggering actual contract and market communication / operation processes.

To access the test enviroment, you have to use different hostnames for your API request.

| API                   | Test environment            | Production environment |
| :-------------------- | :-------------------------- | :--------------------- |
| Authentication server | `test-auth.rabot-charge.de` | `auth.rabot-charge.de` |
| API server            | `test-api.rabot-charge.de`  | `api.rabot-charge.de`  |

<Warning>
  Note that your client credentials are different between TEST and PROD environment. Remember to use the correct set of credentials depending on the environment.
</Warning>

### Automating OAuth 2.0 Token Management

This guide shows you how to implement automated token management in your RABOT Partner API integration, ensuring your scripts maintain uninterrupted access without manual intervention.

***

### Token Lifecycle

```mermaid theme={null}
sequenceDiagram
    participant Script as Your Script
    participant Storage as Token Cache
    participant Auth as RABOT Auth Server
    participant API as RABOT API

    Note over Script,API: INITIAL AUTHENTICATION
    Script->>Auth: POST /connect/token<br/>(client credentials)
    Auth->>Script: access_token (expires in ~1 hour)
    Script->>Storage: Cache token + expiry time
    Script->>API: API Request<br/>(Bearer access_token)
    API->>Script: Success Response

    Note over Script,API: AUTOMATED RE-AUTHENTICATION
    Script->>Storage: Check token expiry
    Storage->>Script: Token expired!
    
    Script->>Auth: POST /connect/token<br/>(client credentials)
    Auth->>Script: new access_token
    Script->>Storage: Update cache
    
    Script->>API: API Request<br/>(Bearer new access_token)
    API->>Script: Success Response
```

**Key Points:**

* Tokens expire after \~1 hour (3599 seconds)
* No refresh tokens - re-authenticate with client credentials when expired
* Proactive token renewal recommended (don't wait for 401 errors)

***

### Token Request

Use your client credentials to obtain an access token:

<Info>
  replace CLIENT\_ID and CLIENT\_SECRET with the credentials you received from Rabot Charge. See [Partner setup](/guides/partner_setup)
</Info>

```cURL Example API request theme={null}
curl -L "auth.rabot-charge.de/connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id={{CLIENT_ID}}" \
-d "client_secret={{CLIENT_SECRET}}" \
-d "grant_type=client_credentials" \
-d "scope=api:partner"
```

#### Scopes

You need to specify, which scopes you want to include in the token by specifying them in `scope` parameter.

<Note>
  **Multiple Scopes:** Separate multiple scopes with spaces, e.g., `api:partner create:orders`
</Note>

The following scopes are available for **Whitelabel Partners**:

| Scope                    | Description                                                                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `api:partner`            | permission to access Partner API, required for all API requests                                                                       |
| `create:orders`          | permission to create orders                                                                                                           |
| `role:finance-reporting` | permission to access customer and contract data, limited to finance reporting related information                                     |
| `role:customer-support`  | permission to access customer and contract data, limited to customer support related information (includes `role: finance-reporting`) |
| `role:application`       | permission to access all customer and contract data (includes `role: finance-reporting` and `role:customer-support` )                 |

The following scopes are available for **HEMS / 3rd Party Partners**:

| Scope         | Description                                                     |
| ------------- | --------------------------------------------------------------- |
| `api:partner` | permission to access Partner API, required for all API requests |

<Warning>
  In order to access further customer or contract specific information e.g. Working Price via the [metrics endpoint](/api-reference/customers/get_contract_metrics), you will need to integrate the [3rd Party Authorization flow](/guides/customer_linking).

  Once the RABOT customer has authorized the data exchange between our platforms, you will be able to access all endpoint under the /customers path.
</Warning>

The following scopes are available for **Sales Affilliate Partners**:

| Scope                    | Description                                                                                       |
| ------------------------ | ------------------------------------------------------------------------------------------------- |
| `api:partner`            | permission to access Partner API, required for all API requests                                   |
| `create:orders`          | permission to create orders                                                                       |
| `role:finance-reporting` | permission to access customer and contract data, limited to finance reporting related information |

<Note>
  To use scopes, you need to have them assigned to your API client by RABOT administrators. If you feel you should have a scope, that you don't have, please contact our [Integration Management team](mailto:j.ohara@rabot-charge.de).
</Note>

### Token Response

If successful, the authentication server responds with a HTTP/200 status code, and the response body contains a structure with the access token

```json theme={null}
{
  "access_token": "eyJhbGciOiJS....QnkY36d_ac",
  "token_type": "Bearer",
  "expires_in": 3599
}
```

In all requests to the partner API, include the access token as **Bearer token** in the HTTP authorization header:

```cURL Example API request theme={null}
curl -L "https://api.rabot-charge.de/partner/v1/tariffs" \
-H "Authorization: Bearer eyJhbGciOiJS....QnkY36d_ac"
```

<Note>
  Note that the token only has a limited life time; when the life time has expired, you will need to request a new token from the authentication server.
</Note>

### Best Practices

### 1. Proactive Token Renewal

Don't wait for tokens to expire - renew them proactively:

```python theme={null}
# Good: Check before each request
def ensure_valid_token(self):
    if datetime.now() >= self.token_expires_at:
        self.authenticate()

# Better: Renew 5 minutes before expiry
def ensure_valid_token(self):
    buffer = timedelta(minutes=5)
    if datetime.now() >= (self.token_expires_at - buffer):
        self.authenticate()
```

### 2. Secure Credential Storage

<Warning>
  **Never hardcode credentials** in your source code or commit them to version control.
</Warning>

**Recommended approaches:**

```python theme={null}
# Environment variables (development/production)
import os
client = RabotAPIClient(
    client_id=os.environ['RABOT_CLIENT_ID'],
    client_secret=os.environ['RABOT_CLIENT_SECRET']
)

# Configuration file (with restricted permissions)
import json
with open('/secure/path/config.json') as f:
    config = json.load(f)
    client = RabotAPIClient(
        client_id=config['client_id'],
        client_secret=config['client_secret']
    )

# Secret management service (production)
# AWS Secrets Manager, Azure Key Vault, etc.
```

### 3. Error Handling

Always handle authentication errors gracefully:

```python theme={null}
def authenticate(self):
    try:
        response = requests.post(self.auth_url, data=data)
        response.raise_for_status()
        # ... process token
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 401:
            raise Exception("Invalid client credentials")
        elif e.response.status_code == 403:
            raise Exception("Insufficient scopes or permissions")
        else:
            raise Exception(f"Authentication failed: {e}")
    except requests.exceptions.RequestException as e:
        raise Exception(f"Network error during authentication: {e}")
```

### 4. Logging (Without Exposing Secrets)

Log authentication events, but never log tokens or credentials:

```python theme={null}
import logging

def authenticate(self):
    logging.info("Requesting new access token...")
    # ... get token
    logging.info(f"Token obtained, expires at {self.token_expires_at}")
    # DON'T LOG: logging.debug(f"Token: {self.access_token}")  ❌
```

### 5. Thread Safety (For Multi-threaded Applications)

If your application uses multiple threads, protect token operations:

```python theme={null}
import threading

class ThreadSafeRabotClient(RabotAPIClient):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._token_lock = threading.Lock()
    
    def _ensure_valid_token(self):
        with self._token_lock:
            if not self._is_token_valid():
                self._authenticate()
```

***

### Common Issues & Solutions

### Issue 1: "Invalid client credentials"

**Cause:** Incorrect `client_id` or `client_secret`

**Solution:**

* Verify credentials in your [Partner setup](/guides/partner_setup)
* Check for typos or extra whitespace
* Ensure you're using the correct environment (staging vs. production)

### Issue 2: "Insufficient scopes"

**Cause:** Requesting access to endpoints without the required scopes

**Solution:**

* Review available scopes for your partner type (Whitelabel, HEMS, Sales Affiliate)
* Contact [Integration Management](mailto:j.ohara@rabot.energy) to request additional scopes
* Update your scope list in the authentication request

### Issue 3: Frequent 401 errors

**Cause:** Token expiring between validation check and API request

**Solution:**

```python theme={null}
# Add larger buffer time (e.g., 5 minutes instead of 1)
expires_in = token_data['expires_in'] - 300  # 5 min buffer

# Or validate token immediately before each request
def request(self, ...):
    self._ensure_valid_token()  # Check right before request
    # ... make API call
```

### Issue 4: High authentication rate

**Cause:** Re-authenticating too frequently

**Solution:**

* Increase buffer time to avoid premature re-authentication
* Cache tokens in memory (don't re-authenticate for every request)
* Check your expiry calculation logic

```python theme={null}
# Bad: Re-authenticates every request
def request(self):
    self.authenticate()  # ❌ Don't do this!
    # ... make request

# Good: Only re-authenticate when needed
def request(self):
    self.ensure_valid_token()  # ✓ Only if expired
    # ... make request
```

***

### Testing Your Implementation

### Manual Test

```bash theme={null}
# Test authentication
curl -X POST "https://auth.rabot-charge.de/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  -d "scope=api:partner"

# Use the token
curl -X GET "https://api.rabot-charge.de/partner/v1/tariffs" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

### Testing Checklist

* Initial authentication works
* Token is used in API requests (Bearer header)
* Token expiry is calculated correctly
* Token is renewed before expiry (proactive)
* 401 errors trigger re-authentication
* Credentials are not hardcoded
* Credentials are not logged
* Error handling is robust
* Multi-threaded access is safe (if applicable)

## Questions or Concerns?

Feel free to speak with our [Integration Management Team](mailto:j.ohara@rabot.energy) or alternatively, ask our built-in AI assistant, Rabotini 🤖 (several languages supported).
