Skip to content

Authentifizierung ​

Die eBOnaut API authentifiziert deine Requests ausschließlich über HMAC-signierte Request-Umschläge. Es gibt keine Session-Tokens oder API-Keys im Header – die gesamte Authentifizierung steckt im Request-Body.

Zwei HMAC-Ebenen ​

Es existieren zwei Arten von Zugangsdaten, je nach Kontext der Anfrage:

EbeneHerkunftVerwendung
Partner-HMACWird von eBOnaut initial ausgestelltcodesetup/set und codesetup/get – der komplette Pairing-Flow zum Anbinden neuer Kund:innen
Kunden-HMACEinmalig aus codesetup/get, nachdem die Kund:in die Verbindung aktiviert hatAlle übrigen Endpunkte – jeder Request läuft im Kontext der Kund:in, deren Zugangsdaten verwendet werden

Speichere pro angebundener Kund:in ein eigenes HMAC-Triple und wähle je nach Request den passenden Satz aus. Die Partner-Zugangsdaten nutzt du ausschließlich für das Onboarding.

Prinzip ​

Jeder Request enthält statt der eigentlichen Parameter einen signierten Umschlag mit drei Feldern:

json
{
  "hmac_ID": "<22-stellige numerische Key-ID>",
  "message": "<iv_hex>:<verschlüsselte_nachricht_hex>",
  "hmac": "<HMAC-SHA256 der message, hex>"
}
  • hmac_ID – ID des HMAC-Keys (genau 22 Zeichen, numerisch), wird dir von eBOnaut zugewiesen
  • message – die mit AES-256-CBC verschlüsselte Nachricht (Format: iv:ciphertext, beides hex-kodiert)
  • hmac – HMAC-SHA256 über den kompletten message-String, berechnet mit dem Secret Key

Die Nachricht (message) ​

Die verschlüsselte Nachricht ist ein JSON-Objekt:

json
{
  "timestamp": 1761500000,
  "hmac_unique": "beliebige-eindeutige-id",
  "body": {
    "...": "die eigentlichen Request-Parameter"
  }
}
FeldBedeutung
timestampUnix-Zeitstempel der Erstellung – Nachrichten sind 5 Minuten gültig
hmac_uniqueEindeutige ID pro Request – Wiederverwendung wird abgelehnt (Replay-Schutz)
bodyDie eigentlichen Request-Parameter des Endpunkts

Ablauf beim Erstellen eines Requests ​

  1. Nachricht bauen – JSON-Objekt mit timestamp, hmac_unique und body erstellen
  2. Verschlüsseln – Nachricht mit AES-256-CBC und dem encryption_key verschlüsseln (zufälliger IV pro Request), als iv_hex:ciphertext_hex formatieren
  3. Signieren – hmac = HMAC_SHA256(message, secret_key) berechnen, hex-kodiert
  4. Senden – hmac_ID, message, hmac als Request-Body (form-data oder JSON)

Beispiele ​

Alle Beispiele bauen den gleichen Umschlag: Nachricht als JSON bauen → mit AES-256-CBC verschlüsseln (iv_hex:ciphertext_hex) → HMAC-SHA256 über den message-String → als hmac_ID, message, hmac senden.

PHP ​

php
$body = ['search' => 'DE.Justiz.f8d8388f-1a64-'];

$iv = random_bytes(16);
$encrypted = openssl_encrypt(
    json_encode([
        'timestamp'   => time(),
        'hmac_unique' => bin2hex(random_bytes(8)),
        'body'        => $body,
    ]),
    'aes-256-cbc',
    $encryptionKey,      // von eBOnaut ausgestellt
    OPENSSL_RAW_DATA,
    $iv
);

$message = bin2hex($iv) . ':' . bin2hex($encrypted);

$payload = [
    'hmac_ID' => $hmacId,                            // 22-stellige Key-ID
    'message' => $message,
    'hmac'    => hash_hmac('sha256', $message, $secretKey),
];

Node.js ​

js
const crypto = require('node:crypto')

const hmacId = '<hmac_id>'             // 22-stellige Key-ID
const secretKey = '<secret_key>'       // von eBOnaut ausgestellt
const encryptionKey = '<enc_key>'      // 32-stellig

const body = { search: 'DE.Justiz.f8d8388f-1a64-' }
const iv = crypto.randomBytes(16)

const cipher = crypto.createCipheriv(
  'aes-256-cbc',
  Buffer.from(encryptionKey, 'utf8'),
  iv
)
const encrypted = Buffer.concat([
  cipher.update(JSON.stringify({
    timestamp: Math.floor(Date.now() / 1000),
    hmac_unique: crypto.randomBytes(8).toString('hex'),
    body,
  }), 'utf8'),
  cipher.final(),
])

const message = `${iv.toString('hex')}:${encrypted.toString('hex')}`

const form = new FormData()
form.append('hmac_ID', hmacId)
form.append('message', message)
form.append('hmac', crypto.createHmac('sha256', secretKey).update(message).digest('hex'))

const res = await fetch('https://api.ebonaut.io/contact/search', {
  method: 'POST',
  headers: { Origin: 'https://partner.example.com' },
  body: form,
})
console.log(await res.json())

Python ​

python
import hashlib
import hmac
import json
import os
import time

import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

HMAC_ID = '<hmac_id>'           # 22-stellige Key-ID
SECRET_KEY = '<secret_key>'     # von eBOnaut ausgestellt
ENCRYPTION_KEY = '<enc_key>'    # 32-stellig

body = {'search': 'DE.Justiz.f8d8388f-1a64-'}
iv = os.urandom(16)

plaintext = json.dumps({
    'timestamp': int(time.time()),
    'hmac_unique': os.urandom(8).hex(),
    'body': body,
})

cipher = AES.new(ENCRYPTION_KEY.encode(), AES.MODE_CBC, iv)
encrypted = cipher.encrypt(pad(plaintext.encode(), AES.block_size))

message = iv.hex() + ':' + encrypted.hex()

payload = {
    'hmac_ID': HMAC_ID,
    'message': message,
    'hmac': hmac.new(SECRET_KEY.encode(), message.encode(), hashlib.sha256).hexdigest(),
}

res = requests.post(
    'https://api.ebonaut.io/contact/search',
    headers={'Origin': 'https://partner.example.com'},
    data=payload,
)
print(res.json())

cURL ​

bash
curl -X POST "https://api.ebonaut.io/contact/search" \
  -H "Origin: https://partner.example.com" \
  -F "hmac_ID=<hmac_id>" \
  -F "message=<message>" \
  -F "hmac=<hmac>"

Fehlerfälle ​

Die API lehnt den Umschlag mit 403 ab, wenn:

  • hmac_ID, message oder hmac fehlen oder das Format nicht stimmt
  • der HMAC-Key unbekannt oder abgelaufen ist (optionales hmac_expiration)
  • die Signatur nicht zur Nachricht passt
  • der timestamp älter als 5 Minuten ist
  • hmac_unique bereits verwendet wurde

Uhrzeit synchronisieren

Dein Server muss per NTP synchronisiert sein. Weicht die Systemzeit um mehr als ca. 4 Minuten ab, werden gültige Requests als abgelaufen abgelehnt.

Zugangsdaten ​

Jeder Satz besteht aus hmac_ID, secret_key und encryption_key. Wie du an die Partner- und Kunden-Zugangsdaten kommst und wie lange sie gültig sind, steht im Pairing-Ablauf.

secret_key und encryption_key behandelst du wie Passwörter: Leg sie nicht im Quellcode, in Logs oder in Client-Anwendungen ab.

Origin-Prüfung ​

Zusätzlich zur HMAC-Signatur prüft die API den Origin-Header gegen eine Allowlist:

  • Requests ohne Origin oder mit nicht freigegebenem Origin → 403
http
Origin: https://partner.example.com

Mit 🌈 entwickelt in Berlin 🐻 & Köln ⛪
Hosting zu 100% in Deutschland 🇩🇪