# Demonstration of Proof-of-Possession (DPoP)

## Introduction

The Demonstration of Proof-of-Possession(DPoP) is a mechanism to tie an access\_token to the client who gets it. The client will have to provide a proof of possession before the access\_token can be used.

<figure><img src="https://1982108655-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fk67iNluSpweCPqhbIY5t%2Fuploads%2FJe69vANdS0wMDXE1YU5P%2Fimage.png?alt=media&#x26;token=120021f9-9a33-4619-b877-84373d2998b2" alt=""><figcaption><p>DPoP Mechanism</p></figcaption></figure>

**1. Client application generates an ephemeral (One time) keypair on each API request.**

{% hint style="info" %}
Please ensure a new ephemeral keypair is generated on each request to ensure DPoP Proof is always unique per transaction.
{% endhint %}

* Ephemeral public key (JWK)
* Ephemeral private key

With the following information:&#x20;

* alg: ES256
* use: sig

***

**2. Client application generates the DPoP Proof JWT(for /token API)**

* Embed the DPoP Proof JWTephemeral public key (JWK) into the header of the DPoP Proof JWT DPoP Proof JWT
* Sign the DPoP Proof JWT using the DPoP Proof JWT ephemeral private key

***

**3. Client application appends ephemeral public key (JWK) thumbprint into the payload of the client\_assertion (cnf.jkt)**

Refer to Generate [Client Assertion](https://docs.developer.singpass.gov.sg/docs/legacy-myinfo-v3-v4/technical-specifications/myinfo-v4/technical-concepts/client-assertions)

{% hint style="info" %}
This step ensures that the identical client application generates the DPoP Proof (for Token API) and client\_assertion.
{% endhint %}

***

**4. Client application calls the /token API to request for an access\_token** with the following information:

* DPoP Proof (for Token API)
* client\_assertion
* authcode

***

**5. AuthZ server validates and embeds the ephemeral public key (JWK) thumbprint of the DPoP Proof JWT (for /token API) into the access\_token (cnf.jkt).**&#x20;

{% hint style="info" %}
This step ensures that the access\_token can only be used by the client application.
{% endhint %}

***

**6. AuthZ server returns access\_token to the client application with token\_type as DPoP.**&#x20;

***

**7. Client application generates another DPoP Proof JWT (for /person API):**

{% hint style="info" %}
This step ensures that the access\_token can only be used by the client application.
{% endhint %}

***

**8. Client application calls the /person API to request for the person data (Resource)** with the following information:

* DPoP Proof (for Person API)
* access\_token

***

**9. Resource server validates the payload (ath) and ensures the ephemeral public key (JWK) thumbprint of the DPoP Proof JWT (for /person API) matches the access\_token hash and cnf.jkt.**&#x20;

{% hint style="info" %}
This step ensures that the access\_token belongs to the client application that generates the DPoP Proof (Person API).&#x20;
{% endhint %}

***

**10. Resource server response with the person data.**&#x20;

***

## **Generate Ephemeral keys**

**Sample Code:**

```
async function generateEphemeralKeys() {
  let options = {
    namedCurve: "P-256",
    publicKeyEncoding: {
      type: "spki",
      format: "pem",
    },
    privateKeyEncoding: {
      type: "sec1",
      format: "pem",
    },
  };
     
  let ephemeralKeyPair = crypto.generateKeyPairSync("ec", options);
 
  return ephemeralKeyPair;
}


```

***

## Generate DPoP Proof JWT

The claims (Refer to <https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop#name-dpop-proof-jwt-syntax>) expected in the DPoP Proof JWT are:&#x20;

| PARAMETER | DESCRIPTION                                                                                                                                                                                                             |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| typ       | Type - Type (Header), value "dpop+jwt"                                                                                                                                                                                  |
| alg       | Algorithm (Header) - digital signature algorithm identifier as per RFC7518 (Refer to <https://datatracker.ietf.org/doc/html/rfc7518>). MUST NOT be none or an identifier for a symmetric algorithm (MAC), value "ES256" |
| jwk       | JSON Web Key (Header) - public key chosen by the client. MUST NOT contain the private key.                                                                                                                              |
| jti       | JWT ID (Payload) - unique identifier                                                                                                                                                                                    |
| htu       | HTTP URL (Payload) - HTTP URI used for the request, without query (?) and fragment parts (#)                                                                                                                            |
| htm       | HTTP Method (Payload) - HTTP method for the request to which the JWT is attached                                                                                                                                        |
| iat       | Issued At (Payload) - current timestamp                                                                                                                                                                                 |
| exp       | Expiry (Payload) - expiry timestamp                                                                                                                                                                                     |
| ath       | Access token hash (Payload) - The base64url encoded SHA-256 hash of the ASCII encoding of the associated access token's value (Required only for /person call after DPoP-bound access token is issued)                  |
|           |                                                                                                                                                                                                                         |

**DPoP Proof Sample**

**Token API**

```
{
  "typ": "dpop+jwt",
  "jwk": {
    "kty": "EC",
    "kid": "M2OJVTdfiUw9C1HQkO1vTijLXGOypcFuT5wd4-5WdzE",
    "crv": "P-256",
    "x": "n92tLt2RNoBgB3jbOkq61wl_33USS08tS-GR7de0Mf0",
    "y": "3riG1jcEY8BLZdR8fseAkXA-RoIov_x9C_bG3JXVUq4",
    "use": "sig",
    "alg": "ES256"
  },
  "alg": "ES256"
}.
{
  "htu": "https://sit.api.myinfo.gov.sg/com/v4/token",
  "htm": "POST",
  "jti": "bWDY6aTCnAGKWtCUjYLVIVmoEmB4XarepsBD85GC",
  "iat": 1662714998,
  "exp": 1662715118
}.
[signature]
```

**Person API**

```
{
  "typ": "dpop+jwt",
  "jwk": {
    "kty": "EC",
    "kid": "M2OJVTdfiUw9C1HQkO1vTijLXGOypcFuT5wd4-5WdzE",
    "crv": "P-256",
    "x": "n92tLt2RNoBgB3jbOkq61wl_33USS08tS-GR7de0Mf0",
    "y": "3riG1jcEY8BLZdR8fseAkXA-RoIov_x9C_bG3JXVUq4",
    "use": "sig",
    "alg": "ES256"
  },
  "alg": "ES256"
}.
{
  "htu": "https://sit.api.myinfo.gov.sg/com/v4/person/915267f0-5939-0230-78e7-b8cdbaab8518",
  "htm": "GET",
  "jti": "XFj7vBWCOlpI2Qyuxi4R7l2BTwFWDwZu1lWDT47p",
  "iat": 1662715005,
  "exp": 1662715125,
  "ath": "Eh9xM2CDQyrI3OMLJJJDhtmQeakdYYTDckNtklRQOVw"
}.
[signature]
```

**Sample Code:**

```
// ath: Base64urlencoded Hash of the access_token
 
async function generateDpop(url, ath, method, ephemeralKeyPair) {
  let now = Math.floor(Date.now() / 1000);
  let payload = {
    htu: url,
    htm: method,
    jti: generateRandomString(40),
    iat: now,
    exp: now + 120,
  };
     
  if (ath) {
    payload.ath = ath;
  }
 
  let privateKey = await jose.JWK.asKey(ephemeralKeyPair.privateKey, "pem");
  let jwk = (await jose.JWK.asKey(ephemeralKeyPair.publicKey, "pem")).toJSON(true);
  jwk.use = "sig";
  jwk.alg = "ES256";
  let DPoP = await jose.JWS.createSign(
    { format: "compact", fields: { typ: "dpop+jwt", jwk: jwk } },
    { key: privateKey, reference: false }
  )
    .update(JSON.stringify(payload))
    .final();
  return DPoP;
}
```
