eimHub developers

Authentication

Every API call carries an OAuth 2.0 access token: Authorization: Bearer <token>. A platform obtains tokens for its service account with the client credentials grant at the token endpoint of the realm (https://id.eimhub.example/realms/eimhub/protocol/openid-connect/token in these examples; your environment's is in the console's API access panel and in the oauth2 security scheme of the API reference).

A service account authenticates in one of two ways, chosen when it is created and fixed afterwards.

Roles

A token says who you are; your roles decide what you may call. Each operation in the API reference starts with a Roles line naming the predefined roles that may call it — for example Roles: TenantAdmin, SubTenantAdmin, Operator, Integrator. A call by a principal holding none of them is answered 403 FORBIDDEN.

Some rules are not role lists, so the Roles line cannot show them:

Client secret

The token request carries the client id and the secret:

curl -s https://id.eimhub.example/realms/eimhub/protocol/openid-connect/token \
  -d grant_type=client_credentials \
  -d client_id=sa-acme-erp \
  -d client_secret="$CLIENT_SECRET"

The secret is shown once, when the account is created or its secret rotated. Keep it in your secret store; eimHub cannot show it again.

Secret rotation

An administrator rotates the secret in the console (Rotate secret) or with POST /api/v1/service-accounts/{user_id}:rotate-secret. The answer carries the new secret once and previous_secret_expires_at:

Key pair (private_key_jwt)

Your platform holds a private key; eimHub holds only the public key. The token request carries a short-lived JWT — the client assertion (RFC 7523) — that you sign with the private key:

Claim Value
header kid the id of the key that signed it
iss, sub your client id
aud the token endpoint
jti a unique value per assertion
exp at most 60 seconds ahead (iat = now)

Keys are EC P-256 (ES256) or RSA of 2048 bits or more (RS256 / PS256), each with a distinct kid.

import time, uuid
import jwt, requests  # pip install 'pyjwt[crypto]' requests

TOKEN_URL = "https://id.eimhub.example/realms/eimhub/protocol/openid-connect/token"
CLIENT_ID = "sa-acme-erp"
now = int(time.time())
assertion = jwt.encode(
    {
        "iss": CLIENT_ID,
        "sub": CLIENT_ID,
        "aud": TOKEN_URL,
        "jti": uuid.uuid4().hex,
        "iat": now,
        "exp": now + 60,
    },
    open("private-key.pem").read(),
    algorithm="ES256",
    headers={"kid": "acme-2026-10"},
)
token = requests.post(
    TOKEN_URL,
    data={
        "grant_type": "client_credentials",
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": assertion,
    },
).json()["access_token"]

eimHub learns your public keys in one of two ways:

Never send a private key: eimHub refuses a key with private members, and a private key that was sent anywhere must be replaced.

Key rotation

Ending a compromised key

Removing a key from your published set does not end it: the identity provider may keep accepting a key it has already read. To end a compromised key:

  1. replace the keys with PUT /api/v1/service-accounts/{user_id}/keys and {"keys": [...]} — registered keys without the compromised one — which takes effect from the next token request; or
  2. have an administrator delete the service account.

If the PUT answers 503 DEPENDENCY_UNAVAILABLE, your keys are stored but not yet in force: repeat the same request.

Token caching

Access tokens are valid for 15 minutes (expires_in in the token response). Cache the token and reuse it for every call until shortly before it expires; request a new one then, or when a call answers 401 UNAUTHENTICATED. Requesting a token per call adds latency and counts against the identity provider's limits.