Elk endpoint van de Signing API, met de parameters die Cleverbase aanneemt en de waarden die het vereist. De flow die ze aan elkaar rijgt is het hoofdstuk "De ondertekenflow"; dit hoofdstuk is om in te zoeken terwijl je code schrijft.
Basis-URL: https://connect.acc.cleverbase.com op acceptatie, https://connect.cleverbase.com in productie. De API volgt CSC API v1.0.4 met OAuth 2.0 (RFC 6749); waar de CSC-specificatie meer toestaat dan Cleverbase ondersteunt, zegt deze referentie wat Cleverbase ondersteunt.
GET /oauth2/authorize
CSC API v1.0.4, §8.3 · RFC 6749, §3.1
Start een autorisatie. Twee scopes, twee doelen: service levert een Bearer-token voor het opvragen van de credential, credential levert de signature activation data (SAD) voor één set hashes. Dit is een redirect in de browser, geen aanroep uit je backend.
| Parameter | Verplicht | Type | Toelichting |
|---|---|---|---|
response_type | ja | string | Altijd code. |
client_id | ja | string | Je geregistreerde client-identifier, zie Je client registreren. |
redirect_uri | ja | string | Een geregistreerde redirect-URL. Moet gelijk zijn aan die je naar het token-endpoint stuurt. |
scope | ja | string | service of credential. |
state | ja | string | Tot 255 bytes, komt onveranderd terug. Jouw greep op de flow; bewaar hem server-side en eenmalig. |
lang | nee | string | Taalvoorkeur, bijvoorbeeld en-US. |
credentialID | voorwaardelijk | string | Verplicht bij scope=credential. |
numSignatures | voorwaardelijk | integer | Verplicht bij scope=credential. Maximaal 50. |
hash | voorwaardelijk | string | Verplicht bij scope=credential. Komma-gescheiden, base64url gecodeerde hashes; het aantal moet gelijk zijn aan numSignatures. |
account_token | nee | string | Zie Account tokens. |
Het antwoord is een redirect naar je redirect_uri met code en state, of met error en error_description en dezelfde state.
GET /oauth2/authorize?response_type=code&client_id=<client_id>
&redirect_uri=<redirect_uri>&scope=service&lang=en-US&state=12345678:root
HTTP/1.1 302 Found
Location: <redirect_uri>?code=FhkXf9P269L8g&state=12345678:root
GET /oauth2/authorize?response_type=code&client_id=<client_id>
&redirect_uri=<redirect_uri>&scope=credential
&credentialID=GX0112348&numSignatures=1
&hash=MTIzNDU2Nzg5MHF3ZXJ0enVpb3Bhc2RmZ2hqa2zDtnl4
&state=12345678:root
HTTP/1.1 302 Found
Location: <redirect_uri>?code=HS9naJKWwp901hBcK348IUHiuH8374&state=12345678:root
HTTP/1.1 302 Found
Location: <redirect_uri>?error=invalid_request
&error_description=Invalid%20Authorization%20Code&state=12345678:root
POST /oauth2/token
CSC API v1.0.4, §8.4 · RFC 6749, §3.2
Wisselt een autorisatiecode in voor een token. Hetzelfde endpoint voor beide scopes; wat terugkomt verschilt.
| Parameter | Verplicht | Type | Toelichting |
|---|---|---|---|
grant_type | ja | string | Altijd authorization_code. |
code | ja | string | De code uit de redirect. |
client_id | ja | string | Je client-identifier. |
redirect_uri | ja | string | Dezelfde redirect-URL als in het autorisatieverzoek. |
Stuur je clientgegevens als HTTP basic auth op client_id:client_secret (RFC 6749, §2.3.1), en de parameters als application/x-www-form-urlencoded.
| Veld in het antwoord | Verplicht | Toelichting |
|---|---|---|
access_token | ja | Bij scope=service een Bearer-token voor de /csc/v1/*-aanroepen; bij scope=credential de signature activation data (SAD). |
token_type | ja | Bearer of SAD. |
expires_in | nee | Seconden. In de praktijk 3600 voor een service-token en 300 voor een SAD. |
POST /oauth2/token HTTP/1.1
Authorization: Basic Y2xpZW50SUQ6cGFzc3dvcmQ
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=FhkXf9P269L8g
&client_id=<client_id>&redirect_uri=<redirect_uri>
HTTP/1.1 200 OK
{ "access_token": "4/CKN69L8gdSYp5_pwH3XlFQZ3ndFhkXf9P2_TiHRG-bA",
"token_type": "Bearer", "expires_in": 3600 }
HTTP/1.1 200 OK
{ "access_token": "3XlFQZ3ndFhkXf9P24/CKN69L8gdSYp5H3XlFQZ3ndFhkXf9P2",
"token_type": "SAD", "expires_in": 300 }
POST /csc/v1/credentials/list
Welke credentials de ondertekenaar heeft. Vraagt het service-Bearer-token.
| Parameter | Verplicht | Type | Toelichting |
|---|---|---|---|
maxResults | nee | integer | Maximaal aantal credentialIDs in het antwoord. |
pageToken | nee | string | Opaak token voor de volgende pagina. |
clientData | nee | string | Wordt doorgegeven, zie CSC 7.5. |
| Veld in het antwoord | Verplicht | Toelichting |
|---|---|---|
credentialIDs | ja | Array met credential-identifiers. |
POST /csc/v1/credentials/list HTTP/1.1
Authorization: Bearer 4/CKN69L8gdSYp5_pwH3XlFQZ3ndFhkXf9P2_TiHRG-bA
Content-Type: application/json
{ "maxResults": 10 }
HTTP/1.1 200 OK
{ "credentialIDs": [ "GX0112348", "HX0224685" ] }
POST /csc/v1/credentials/info
De certificaatketen en de eigenschappen van de sleutel. Vraagt het service-Bearer-token. Dit is de aanroep die je in staat stelt de plaatshouder te bouwen en de hash te berekenen, dus hij komt voor al het PDF-werk.
| Parameter | Verplicht | Type | Toelichting |
|---|---|---|---|
credentialID | ja | string | Uit credentials/list. |
| Veld in het antwoord | Verplicht | Toelichting |
|---|---|---|
key/status | ja | enabled (bruikbaar om te ondertekenen) of disabled. Disabled gebeurt als de eigenaar de sleutel heeft uitgezet, of als wij hebben vastgesteld dat het certificaat is verlopen of ingetrokken. Controleer dit voordat je verder gaat. |
key/algo | ja | Array met OID's van de ondersteunde sleutelalgoritmes. |
key/len | ja | Sleutellengte in bits. Deel door 8 voor de handtekeninglengte die je moet reserveren. |
cert/certificates | ja | Een of meer base64-gecodeerde X.509v3-certificaten, ondertekenaar eerst. |
authMode | ja | Altijd oauth2code. |
POST /csc/v1/credentials/info HTTP/1.1
Authorization: Bearer 4/CKN69L8gdSYp5_pwH3XlFQZ3ndFhkXf9P2_TiHRG-bA
Content-Type: application/json
{ "credentialID": "GX0112348" }
HTTP/1.1 200 OK
{ "key": { "status": "enabled", "algo": [ "1.2.840.113549.1.1.1" ], "len": 2048 },
"cert": { "certificates": [ "MIIGDSGDGSD...." ] },
"authMode": "oauth2code" }
POST /csc/v1/signatures/signHash
Ondertekent je hash of hashes. Vraagt beide tokens: het service-Bearer-token in de header en de SAD in de body.
| Parameter | Verplicht | Type | Toelichting |
|---|---|---|---|
credentialID | ja | string | De credential waarvoor de SAD is afgegeven. |
SAD | ja | string | Het access_token uit de uitwisseling met scope credential. |
hash | ja | array van string | De hashes, in gewone base64 (niet base64url zoals in de autorisatie-URL). SHA-256. |
hashAlgo | ja | string | Moet 2.16.840.1.101.3.4.2.1 zijn (SHA-256). |
signAlgo | ja | string | Moet 1.2.840.113549.1.1.1 zijn (rsaEncryption). Zie de noot hieronder. |
clientData | nee | string | Wordt doorgegeven, zie CSC 7.5. |
| Veld in het antwoord | Verplicht | Toelichting |
|---|---|---|
signatures | ja | Array met handtekeningwaarden, in dezelfde volgorde als de hashes die je stuurde. |
POST /csc/v1/signatures/signHash HTTP/1.1
Authorization: Bearer 4/CKN69L8gdSYp5_pwH3XlFQZ3ndFhkXf9P2_TiHRG-bA
Content-Type: application/json
{ "credentialID": "GX0112348",
"SAD": "3XlFQZ3ndFhkXf9P24/CKN69L8gdSYp5H3XlFQZ3ndFhkXf9P2",
"hash": [ "sTOgwOm+474gFj0q0x1iSNspKqbcse4IeiqlDg/HWuI=" ],
"hashAlgo": "2.16.840.1.101.3.4.2.1",
"signAlgo": "1.2.840.113549.1.1.1" }
HTTP/1.1 200 OK
{ "signatures": [ "KedJuTob5gtvYx9qM3k3gm7kbLBwVbEQRl26S2tmXjqNND7MRGtoew==" ] }
De waarde van signAlgo, en hoe je bibliotheek het noemt
signAlgo is 1.2.840.113549.1.1.1, en dat is rsaEncryption: het sleutelalgoritme, niet een gecombineerd hash-en-handtekeningalgoritme. Samen met hashAlgo SHA-256 levert dat een PKCS#1 v1.5-handtekening over een SHA-256-digest.
In je PDF-bibliotheek heet diezelfde handtekening sha256WithRSAEncryption (1.2.840.113549.1.1.11), en dat is de OID die in de CMS signatureAlgorithm moet komen. De twee kanten gebruiken dus andere namen voor één ding:
| Waarde | |
|---|---|
signAlgo in het signHash-verzoek | 1.2.840.113549.1.1.1 rsaEncryption |
hashAlgo in het signHash-verzoek | 2.16.840.1.101.3.4.2.1 SHA-256 |
| In de CMS die je bibliotheek bouwt | 1.2.840.113549.1.1.11 sha256WithRSAEncryption |
DSS SignatureAlgorithm | RSA_SHA256 |
| pyHanko | een RSA-certificaat met digest sha256 |
Repareer het verschil niet door rsaEncryption in de CMS te zetten: een validator verwacht daar de gecombineerde OID.
Getallen om te onthouden
| Levensduur service-token | 3600 seconden |
| Levensduur SAD | 300 seconden |
| Hashes per autorisatie | maximaal 50, numSignatures moet met de lijst overeenkomen |
state | tot 255 bytes |
| Codering van de hash, autorisatie-URL | base64url, komma-gescheiden |
| Codering van de hash, signHash-body | gewone base64, JSON-array |
Fouten
Mislukte autorisaties komen terug op de redirect als error plus error_description, met jouw state, en nooit als HTTP-fout naar je backend: het is de browser die met ons praat. Een weigering in de app is ook zo'n redirect, dus behandel "error" en "de ondertekenaar zei nee" als één pad. De /csc/v1/*-aanroepen antwoorden je backend direct, dus die fouten komen als HTTP-statuscodes met een body.
Er is geen webhook. Komt de ondertekenaar nooit terug, dan hoor je niets; zie "De reis van de ondertekenaar" voor hoe je dat afkapt.