Formatting DPoP proofs

This document describes how a DPoP proof should be included in the request to HelseID and an API, respectively.

DPoP Header in the HTTP Request

A DPoP proof should be included in the header named DPoP in all calls to the token endpoint in HelseID and all calls to APIs that use DPoP.

The name of the header is DPoP, and the content is the DPoP proof in base64 format:

DPoP eyJhbGciOiJSUzUxMiIsImtpZCI6IkI0Mjc3MjFFNUQxRTc3MDkyNzFDNkM2NzFCQzlFMDdCIiwidHlwIjoiZHBvcFx1MDAyQmp3dCIsImp3ayI6eyJrdHkiOiJSU0EiLCJuIjoiMFZVTEpsSUduNFNNL...X0.eyJqdGkiOiJCMDUwQjYxNzA4RjQyOUU0MzNFQTY5QzJFNUE4RkQ0QiIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL2hlbHNlaWQtc3RzLnRlc3QubmhuLm5vL2Nvbm5lY3QvdG9rZW4iLCJpYXQiOjE2OTI5NDY3MjcsIm5vbmNlIjoiIn0.DSIuBH8nYGuZDVbUggWT7S3iDjMCPR3aH5V9FNG5lmUF3V4rTgSC5YfmhcLFTaYFbeqZA1Ap6WzytlyE1-5kMlS0vWIgiFCViGQDzST-XVWYJQgLKL4Gfs8BXwZhNe2lPQibtjOShTKHRF_hsdSh2u...hSyjHBT4xL7ODGMoh-7c

Structure of a DPoP proof

The figure below shows a valid DPoP proof in its decoded form. The DPoP proof is a standard JWT that is signed with a private key held by the client.

Structure of the Header

The header should consist of the following claims: typ, alg, and jwk.

The typ claim must always be assigned the value dpop+jwt. This indicates that the JWT is a DPoP proof.

The alg claim should specify which signing algorithm has been used in the JWT. The algorithm must be of the ones listed in this document.

The jwk claim should contain the public key that was used to sign the DPoP proof and must be a valid Json Web Key.

Structure of the Payload

The payload (body) of the DPoP proof must always contain the following claims: jti, htm, htu, and iat. When a DPoP proof is used against HelseID, it may also contain the nonce claim. When a DPoP proof is to be used in an API call, it must also include the ath claim.

The jti claim must be a unique value that identifies this particular JWT. HelseID will reject a request with a jti that has been seen before.

The htm claim and the htu claim together identify the URL that the DPoP proof is intended to be used for. htm indicates which HTTP method is being used, htu specifies the URL being called. In the example below, for instance, we are making a POST request to the token endpoint of HelseID's test environment.

The iat claim is a Unix Timestamp that denotes when the JWT was created. HelseID will reject a DPoP proof that is older than 10 seconds.

The nonce claim is used in the second call to HelseID. The nonce value is set in the DPoP-Nonce header in the response from the first call to HelseID. This functionality is described here.

The ath claim should only be used in API calls. Its value should be a SHA-256 hash of the access token that is used in the Authorization header along with the DPoP proof.

Example of a DPoP Proof used with the token endpoint in HelseID (without nonce value):

{ 
  "typ": "dpop+jwt",
  "alg": "RS512",
  "jwk": {
    "kty": "RSA",
    "n": "0VULJlIGn4SM-Y0ZTYOKSpr3KyCbVXK...mVIKTMrAvt72UphUFUkqEwM0Jat2ECuRbOC2VhhovPooYYHNRHvvpQ0",
    "e": "AQAB",
    "alg": "RS512"
  }
}
.
{
  "jti": "23525A88D27BF09EBED7EFF61A21577B",
  "htm": "POST",
  "htu": "https://helseid-sts.test.nhn.no/connect/token",
  "iat": 1692772293
}
.
[Signature]

Example of a DPoP Proof used against an API; the proof contains an ath claim which is a hash of the access token:

{ 
  "typ": "dpop+jwt",
  "alg": "RS512",
  "jwk": {
    "kty": "RSA",
    "n": "0VULJlIGn4SM-Y0ZTYOKSpr3KyCbVXK...mVIKTMrAvt72UphUFUkqEwM0Jat2ECuRbOC2VhhovPooYYHNRHvvpQ0",
    "e": "AQAB",
    "alg": "RS512"
  }
}
.
{
  "jti": "B050B61708F429E433EA69C2E5A8FD4B",
  "htm": "POST",
  "htu": "https://eksempelapi.nhn.no/api",
  "iat": 1692946727,
  "ath":"fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo"
}
.
[Signature]