Authentication
The API supports two authentication mechanisms, one per API version:
| Mechanism | Endpoints | Header |
|---|---|---|
| API key | /api/v1/* |
X-API-KEY |
| HelseID (DPoP) | /api/v2/* |
Authorization: DPoP + DPoP |
/api/internal/health requires no authentication.
API Key (v1)
All v1 endpoints require authentication via an API key. Pass your key in the X-API-KEY header:
curl -H "X-API-KEY: your-api-key-here" \
https://api.example.com/api/v1/treatment-group
Key format
API keys are issued by the service owner and are case-sensitive strings. The format is opaque — treat them as opaque credentials.
Errors
| Status | Meaning |
|---|---|
401 |
Key is missing, empty, or not recognized |
429 |
Rate limit exceeded for this key (see Rate Limiting) |
HelseID (DPoP)
The v2 endpoints (/api/v2/treatment-group, /api/v2/reimbursement-group) are protected with HelseID using DPoP (RFC 9449). Each request requires two credentials:
- A DPoP-bound access token issued by HelseID, sent in the
Authorizationheader. - A DPoP proof — a short-lived JWT you sign with your own DPoP key — sent in the
DPoPheader.
The API only accepts the DPoP authorization scheme. Sending a Bearer token, or an API key, to a v2 endpoint returns 401.
Request headers
| Header | Value |
|---|---|
Authorization |
DPoP <access-token> |
DPoP |
<proof-jwt> — a fresh proof for this specific request |
Access token requirements
The access token is obtained from the HelseID authentication server (see the HelseID developer documentation for the client flow). The token must satisfy:
| Requirement | Value |
|---|---|
| Signed by | The HelseID authorization server |
Audience (aud) |
nhn:nompd |
Scope (scope) |
Must include nhn:nompd/api |
cnf.jkt |
JWK thumbprint of your DPoP public key |
A token without the nhn:nompd/api scope is authenticated but rejected with 403.
DPoP proof requirements
Generate a new proof for every request. The proof is a JWT:
Header
| Claim | Value |
|---|---|
typ |
dpop+jwt |
alg |
RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, or ES512 |
jwk |
Your DPoP public key (must not contain a private key; its thumbprint must match the token's cnf.jkt) |
Payload
| Claim | Value |
|---|---|
ath |
Base64url-encoded SHA-256 hash of the access token |
htm |
The HTTP method (GET) |
htu |
The full request URL — scheme, host, and path, without the query string |
jti |
A unique identifier (e.g. a GUID); proofs with a reused jti are rejected |
iat |
Current time (seconds); the proof is only valid for a few seconds |
The proof must be signed with your DPoP private key.
Example
# access-token: obtained from HelseID (aud=nhn:nompd, scope=nhn:nompd/api, cnf.jkt)
# proof-jwt: signed with your DPoP key, bound to this exact request
curl -H "Authorization: DPoP $ACCESS_TOKEN" \
-H "DPoP: $PROOF_JWT" \
https://api.example.com/api/v2/treatment-group
Replay protection
A proof is bound to a single request and cannot be reused:
- Changing the access token invalidates it (
athmismatch). - Changing the URL path invalidates it (
htumismatch). - Resending the same proof invalidates it (
jtireplay detection).
Errors
| Status | Meaning |
|---|---|
401 |
Token missing, invalid, or expired; Bearer scheme used; proof missing, unsigned, or invalid (ath/htm/htu/iat mismatch, cnf.jkt mismatch, replayed jti) |
403 |
Authenticated, but the access token is missing the nhn:nompd/api scope |