Authentication & Security

How to authenticate with the RideScan API securely, including API keys and OAuth2/JWT token flows

API KeysOAuth2 / JWTFleet SecurityRotation & RevocationBest Practices

At a glance

All requests to https://api.ridescan.cloud must be authenticated over HTTPS. Use either a scoped API key or OAuth2-issued JWT access tokens. In fleets, authenticate robots via a Fleet Manager that dispenses short-lived tokens.

Production tips

  • Never hardcode secrets in firmware or repos.
  • Prefer short-lived tokens over raw API keys on robots.
  • Rotate keys regularly and automate revocation.
  • Scope credentials by role/robot where possible.

Supported Authentication Methods

Choose the method that fits your integration and security posture.

API Key (Bearer)

  • Fast to start; great for server-to-server and CI
  • Scope by role or project; store only in trusted backends
  • Robots should avoid long-lived keys; exchange for short-lived tokens

Header: Authorization: Bearer <API_KEY>

OAuth2 / JWT

  • Access tokens (short-lived) + refresh tokens (longer-lived)
  • Fine-grained scopes and aud/iss claims for validation
  • Best fit for fleets and multi-tenant dashboards

Header: Authorization: Bearer <ACCESS_TOKEN>

Quickstart: API Key

Use a scoped API key for quick server-to-server access.

1) Set your key (do not hardcode)

bash
# macOS/Linux
export RIDESCAN_API_KEY="YOUR_API_KEY"

# Windows (Powershell)
$Env:RIDESCAN_API_KEY="YOUR_API_KEY"

2) Make a test request

bash
curl -sS \
  -H "Authorization: Bearer $RIDESCAN_API_KEY" \
  https://api.ridescan.cloud/api/robots

Expect 200 with your robot list. If you get 401, verify the header and that your key is active.

Python example

python
import os, requests

API_BASE = "https://api.ridescan.cloud"
API_KEY = os.environ.get("RIDESCAN_API_KEY")

headers = {"Authorization": f"Bearer {API_KEY}"}
r = requests.get(f"{API_BASE}/api/robots", headers=headers, timeout=10)
r.raise_for_status()
print(r.json())

Node.js example

javascript
import axios from "axios";

const API_BASE = "https://api.ridescan.cloud";
const API_KEY = process.env.RIDESCAN_API_KEY;

const client = axios.create({
  baseURL: API_BASE,
  timeout: 10000,
  headers: { Authorization: `Bearer ${API_KEY}` },
});

const { data } = await client.get("/api/robots");
console.log(data);

OAuth2 / JWT Token Flow

Use short-lived access tokens with refresh token rotation.

High-level flow

+-----------+         +-------------------+         +------------------+
| Client    |  auth    |  Auth Server       |  tokens  |  RideScan API     |
| (backend) +--------->+  (OAuth2 Provider) +--------->+  (Resource Server)|
+-----------+          +-------------------+          +------------------+
      ^                         |
      |                         | refresh
      +-------------------------+ token rotation

Token endpoints

  • /oauth/token – exchange client creds or auth code for an access token (+ optional refresh token)
  • /oauth/refresh – rotate refresh tokens and mint a new access token

Exchange for tokens

bash
curl -sS -X POST https://api.ridescan.cloud/api/oauth/token \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=robots:read missions:write"

Call an API with JWT

bash
ACCESS_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -sS -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://api.ridescan.cloud/api/missions

Auto-refresh (Python)

python
import os, time, requests

BASE = "https://api.ridescan.cloud"
CLIENT_ID = os.getenv("RIDESCAN_CLIENT_ID")
CLIENT_SECRET = os.getenv("RIDESCAN_CLIENT_SECRET")

def fetch_token():
    r = requests.post(f"{BASE}/oauth/token", data={
        "grant_type": "client_credentials",
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "scope": "robots:read missions:write",
    }, timeout=10)
    r.raise_for_status()
    return r.json()  # { access_token, expires_in, token_type, ... }

tok = fetch_token()
exp_at = time.time() + tok["expires_in"] - 30  # refresh a bit early

def auth_headers():
    global tok, exp_at
    if time.time() >= exp_at:
        tok = fetch_token()
        exp_at = time.time() + tok["expires_in"] - 30
    return {"Authorization": f"Bearer {tok['access_token']}"}

r = requests.get(f"{BASE}/v1/robots", headers=auth_headers(), timeout=10)
print(r.json())

Error Handling & Troubleshooting

Common auth responses and how to fix them.

Typical responses

http
401 Unauthorized
{
  "error": "invalid_token",
  "message": "Access token missing or expired."
}
  • 401: refresh token or re-authenticate; check clock skew (±5 min).

Health checks

bash
# Verify token audience and expiry (JWT)
# (Example using jwt-cli or your own verifier)
jwt decode $ACCESS_TOKEN | jq '{aud, exp, iat, scope}'

Ensure aud matches ridescan-api and exp is in the future.

FAQ

Quick answers for security reviewers.

Do robots store API keys?

Avoid storing long-lived keys on robots. Use a Fleet Manager to mint short-lived per-robot tokens or proxy requests.

How long do tokens last?

Access tokens typically live 15–60 minutes; refresh tokens longer. Configure to your risk tolerance.

How do we rotate keys with zero downtime?

Support overlapping keys (old + new) at the gateway; publish ‘not-before’/‘not-after’ windows and gradually cut over.

What happens if a key leaks?

Immediately revoke in the admin console/API, rotate associated tokens, review logs, and re-issue scoped credentials.

Note: Endpoint paths are illustrative. Replace with the exact endpoints and scopes configured for your RideScan tenant.