API-referentie

Authenticatie

De Tidal Control API gebruikt Bearer-tokens voor authenticatie. Tokens worden uitgegeven door de Keycloak-realm van je tenant via de OAuth 2.0 Device Authorization Grant (RFC 8628). Deze flow is ontworpen voor scripts en CLI-tools die zelf geen browservenster kunnen openen, en het token handelt namens jou — met jouw rechten.

Draait je integratie onbeheerd — een geplande export naar een BI-tool, een server-naar-server-synchronisatie — gebruik dan read-only machine-to-machine-credentials. Zie Machine-to-machine-authenticatie onderaan deze pagina.

Vereisten

Je hebt je tenantnaam nodig — de Keycloak-realm-identifier van je organisatie. Dit is de organisatie-identifier in je portal-URL:

https://portal.tidalcontrol.com/{jouw-tenant}/

Als je portal-URL bijvoorbeeld https://portal.tidalcontrol.com/demo/ is, is je tenantnaam demo.

Vervang in deze handleiding {jouw-tenant} door je eigen tenantnaam.

De authenticatiestroom

De Device Authorization Grant werkt in drie stappen:

  1. Je script vraagt een apparaatcode op bij Keycloak
  2. Jij (of de gebruiker van het script) logt in via een browser-URL
  3. Je script pollt op het toegangstoken zodra de inlog is voltooid

Stap 1 — Apparaatcode opvragen

curl -X POST \
  "https://auth.tidalcontrol.com/realms/{jouw-tenant}/protocol/openid-connect/auth/device" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=portal&scope=openid"

Antwoord:

{
  "device_code": "...",
  "user_code": "ABCD-1234",
  "verification_uri": "https://auth.tidalcontrol.com/realms/{jouw-tenant}/device",
  "verification_uri_complete": "https://auth.tidalcontrol.com/realms/{jouw-tenant}/device?user_code=ABCD-1234",
  "expires_in": 600,
  "interval": 5
}

Stap 2 — Inloggen via browser

Open verification_uri_complete in een browser en log in met je Tidal Control-gegevens. Je script wacht terwijl je dit doet.

Stap 3 — Pollen op het token

Poll het token-endpoint elke interval seconden totdat de inlog is voltooid:

curl -X POST \
  "https://auth.tidalcontrol.com/realms/{jouw-tenant}/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=portal&device_code={device_code}"

Zodra de gebruiker is ingelogd, bevat het antwoord je toegangstoken:

{
  "access_token": "eyJhbGci...",
  "expires_in": 300,
  "refresh_token": "eyJhbGci...",
  "refresh_expires_in": 1800,
  "token_type": "Bearer"
}
Info

Toegangstokens verlopen na 5 minuten. Gebruik de refresh_token om een nieuw toegangstoken op te halen zonder opnieuw in te loggen (zie hieronder).

API-verzoeken versturen

Voeg het toegangstoken toe als Bearer-header aan elk GraphQL-verzoek:

curl -X POST https://portal.tidalcontrol.com/graphql \
  -H "Authorization: Bearer {toegangstoken}" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ tenant { name displayName } }"}'

Volledig Python-voorbeeld

Dit script doorloopt de volledige authenticatiestroom en hergebruikt het token:

import requests
import time
import json

TENANT = "{jouw-tenant}"
BASE_URL = f"https://auth.tidalcontrol.com/realms/{TENANT}/protocol/openid-connect"
CLIENT_ID = "portal"
GRAPHQL_URL = "https://portal.tidalcontrol.com/graphql"


def get_token():
    # Stap 1: Apparaatcode opvragen
    r = requests.post(
        f"{BASE_URL}/auth/device",
        data={"client_id": CLIENT_ID, "scope": "openid"},
    )
    r.raise_for_status()
    device = r.json()

    print(f"\nOpen deze URL in je browser om in te loggen:")
    print(f"  {device['verification_uri_complete']}\n")

    # Stap 2: Pollen op token
    interval = device.get("interval", 5)
    deadline = time.time() + device["expires_in"]

    while time.time() < deadline:
        time.sleep(interval)
        r = requests.post(
            f"{BASE_URL}/token",
            data={
                "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
                "client_id": CLIENT_ID,
                "device_code": device["device_code"],
            },
        )
        if r.status_code == 200:
            print("Authenticatie geslaagd.")
            return r.json()
        body = r.json()
        if body.get("error") == "authorization_pending":
            continue
        if body.get("error") == "slow_down":
            interval += 5
            continue
        r.raise_for_status()

    raise RuntimeError("Authenticatie verlopen.")


def refresh_token(refresh_tok):
    r = requests.post(
        f"{BASE_URL}/token",
        data={
            "grant_type": "refresh_token",
            "client_id": CLIENT_ID,
            "refresh_token": refresh_tok,
        },
    )
    r.raise_for_status()
    return r.json()


def graphql(query, variables, access_token):
    r = requests.post(
        GRAPHQL_URL,
        json={"query": query, "variables": variables},
        headers={"Authorization": f"Bearer {access_token}"},
    )
    r.raise_for_status()
    result = r.json()
    if "errors" in result:
        raise RuntimeError(result["errors"])
    return result["data"]


if __name__ == "__main__":
    token = get_token()
    data = graphql("{ tenant { name displayName } }", {}, token["access_token"])
    print(json.dumps(data, indent=2))

Token vernieuwen

Wanneer het toegangstoken verloopt, gebruik je het refresh-token in plaats van de volledige inlogstroom opnieuw te doorlopen:

token = refresh_token(token["refresh_token"])
access_token = token["access_token"]
Tip

Refresh-tokens verlopen ook (doorgaans na 30 minuten inactiviteit). Als een refresh mislukt, doorloop dan opnieuw de volledige get_token()-stroom.

Machine-to-machine-authenticatie

Voor onbeheerde integraties die zonder iemand erbij draaien — een nachtelijke export naar een BI-tool, een geplande server-naar-server-synchronisatie — gebruik je machine-to-machine-credentials (M2M) in plaats van de device flow. Een M2M-credential is een OAuth 2.0 Client Credentials-client: een client_id en client_secret die je script rechtstreeks inwisselt voor een toegangstoken, zonder browserstap.

M2M-credentials zijn read-only. Ze kunnen queries uitvoeren, maar geen mutaties.

Info

M2M-credentials worden per organisatie ingeschakeld. Zie je de pagina API Credentials niet in je instellingen, mail dan support@tidalcontrol.com om deze te laten inschakelen.

Een credential aanmaken

Voor het aanmaken van credentials heb je de rol Super User nodig.

  1. Ga naar Instellingen → API Credentials.
  2. Klik op Create credential, geef het een label en stel eventueel een vervaldatum in.
  3. Kopieer de client secret direct — deze wordt één keer getoond en kan daarna niet meer worden opgehaald. Bewaar de secret in een secret manager of vault, nooit in platte tekst in je configuratie.

Je beschikt nu over een client_id en een client_secret. Samen vormen deze je credential.

Een token opvragen

Wissel de credential in voor een toegangstoken via de client_credentials-grant. Er is geen browserstap en geen scope-parameter:

curl -X POST \
  "https://auth.tidalcontrol.com/realms/{jouw-tenant}/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id={client_id}" \
  -d "client_secret={client_secret}"

Antwoord:

{
  "access_token": "eyJhbGci...",
  "expires_in": 300,
  "token_type": "Bearer"
}
Info

Deze flow heeft geen refresh-token. Wanneer het toegangstoken verloopt (na ongeveer 5 minuten), vraag je een nieuw token op met dezelfde client_credentials-aanroep.

Voeg het toegangstoken aan elk GraphQL-verzoek toe als Bearer-header, precies zoals bij API-verzoeken versturen hierboven.

Volledig shell-voorbeeld

Zet CLIENT_SECRET op de secret die je hebt gekopieerd, vraag vervolgens een token op en roep de API aan:

export CLIENT_SECRET='<de gekopieerde secret>'

ACCESS_TOKEN=$(curl -s -X POST \
  "https://auth.tidalcontrol.com/realms/{jouw-tenant}/protocol/openid-connect/token" \
  -d "grant_type=client_credentials" \
  -d "client_id={client_id}" \
  -d "client_secret=$CLIENT_SECRET" \
  | jq -r .access_token)

curl -s https://portal.tidalcontrol.com/graphql \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "{ currentTenant { name } }"}'

Wat een credential kan lezen

Een read-only credential kan de volledige dataset van je organisatie lezen — controls, bewijs, personeel, KPI's, rapporten en de gebruikerslijst (namen en e-mailadressen). Behandel een gelekte secret als volledige blootstelling van je organisatiedata en roteer deze direct.

Roteren en intrekken

Gebruik op Instellingen → API Credentials de rijacties (kebabmenu, drie verticale puntjes) om te:

  • Rotate — een nieuwe secret genereren en de oude ongeldig maken. Werk je integratie bij met de nieuwe secret.
  • Revoke — de credential permanent uitschakelen.
Tip

Toegangstokens blijven geldig tot ze verlopen (ongeveer 5 minuten). Een rotatie, intrekking of verloop wordt dus binnen één tokenlevensduur van kracht. Houd rekening met een venster van maximaal 5 minuten voordat de wijziging volledig is doorgevoerd.