Naslag

Account tokens

Bedient je ondertekenapplicatie meerdere klanten via één OAuth-client, stuur dan bij elke autorisatie een account token mee, zodat Cleverbase de handtekening aan de juiste klant kan toerekenen. Eén client, veel klanten: zonder dat token lijkt elke handtekening van jou.

Je hebt dit niet nodig als je client één organisatie bedient.

Hoe het meegaat

Een parameter account_token op GET /oauth2/authorize, naast de andere parameters. Het is een JSON Web Token (JWT) dat je zelf bouwt en ondertekent; Cleverbase controleert het met je client secret.

GET /oauth2/authorize?response_type=code&client_id=<client_id>
    &redirect_uri=<redirect_uri>&scope=service&state=...
    &account_token=<header>.<payload>.<signature>

Het token

base64UrlEncode(header) + "." + base64UrlEncode(payload) + "." + base64UrlEncode(signature)

Header

VeldVerplichtWaarde
typjaJWT
algjaHS256

Payload

ClaimVerplichtBetekenis
subjaHet account-id, door jouw applicatie uniek toegekend aan die klant.
iatjaIssued at, Unix epoch in seconden.
jtijaEen unieke identifier voor dit token.
azpjaAuthorized presenter: het client-id van je OAuth-client.
issneeDe naam van je ondertekenapplicatie.

Signature

HMAC-SHA256 over base64UrlEncode(header) + "." + base64UrlEncode(payload), met als sleutel SHA256(client_secret): de ruwe 32-byte digest van je OAuth client secret, niet het secret zelf en niet de hex- of base64-tekst daarvan.

Dat laatste detail is waar implementaties op stuklopen. In Python:

import base64, hashlib, hmac, json, time, uuid

def b64(raw: bytes) -> str:
    return base64.urlsafe_b64encode(raw).rstrip(b"=").decode()

def account_token(client_id: str, client_secret: str, account_id: str) -> str:
    header = b64(json.dumps({"typ": "JWT", "alg": "HS256"}, separators=(",", ":")).encode())
    payload = b64(json.dumps({
        "sub": account_id,
        "iat": int(time.time()),
        "jti": str(uuid.uuid4()),
        "azp": client_id,
    }, separators=(",", ":")).encode())
    signing_input = f"{header}.{payload}".encode()
    key = hashlib.sha256(client_secret.encode()).digest()   # the digest, not the secret
    sig = hmac.new(key, signing_input, hashlib.sha256).digest()
    return f"{header}.{payload}.{b64(sig)}"

Een verse jti en iat per autorisatie; een token hergebruiken is niet het idee.

Dezelfde constructie staat in de CSC-specificatie in hoofdstuk 8.3.1, als je de bron wilt.

Welke autorisaties het meenemen

Beide rondgangen accepteren het. Stuur het mee op de service-rondgang en op de credential-rondgang van dezelfde flow, met dezelfde sub, zodat de hele handtekening aan één klant wordt toegerekend.

De normatieve tekst is CSC API v1, hoofdstuk 8.3.1.