# 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="/files/fhPFCqD9uPvk47FtQZ99" 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](/docs/legacy-myinfo-v3-v4/technical-specifications/myinfo-v4/technical-concepts/client-assertions.md)

{% 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;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.developer.singpass.gov.sg/docs/legacy-myinfo-v3-v4/technical-specifications/myinfo-v4/technical-concepts/demonstration-of-proof-of-possession-dpop.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
