# Demonstrating Proof of Possession (DPoP)

## Overview

DPoP ([RFC 9449](https://www.rfc-editor.org/rfc/rfc9449.html)) protects your integration from:

1. Authorization code inteception
2. Access token misuse or leakage&#x20;

It works by binding the *authorization code* and *access token* to a private key that only your system controls. allowing only you to use them for [Token Exchange](/docs/technical-specifications/integration-guide/3.-token-exchange.md) and [Requesting For Userinfo](/docs/technical-specifications/integration-guide/5.-requesting-for-userinfo.md) respectively.

#### **When is DPoP Required?**

You must include a **DPoP proof JWT** in the DPoP request header for the following API calls:

* [Pushed Authorization Request](https://docs.developer.singpass.gov.sg/docs/technical-specifications/technical-concepts/pages/wD2EDNbwA7OcSQ788qVw#id-1.-sending-the-pushed-authorization-request)
* [Token Exchange](/docs/technical-specifications/integration-guide/3.-token-exchange.md)
* [Requesting for Userinfo](/docs/technical-specifications/integration-guide/5.-requesting-for-userinfo.md)

If DPoP is missing or invalid the request will be rejected

#### **Key Requirements**

{% hint style="warning" %}
You **must** use the same DPoP key pair across all three requests for a single authentication. You should generate a different ephemeral key for each authentication.
{% endhint %}

* Generate a **new** ephemeral DPoP key pair for each authentication session
* Use the **same key pair across all three requests** (PAR → Token → Userinfo) for that session
* Do not reuse the key pair across different login sessions

#### What Is the DPoP Proof JWT?

The DPoP Proof JWT is a signed JWT (JWS) that proves you own the private key bound to the token — without exposing the private key.

To implement:

* We recommend using a standard JWT library&#x20;
* You may refer to [this list](https://www.jwt.io/libraries?support=sign\&algorithm=es256) to look for a suitable library for your programming language. To learn more about JWTs and their structure, you may read [this article](https://www.jwt.io/introduction).

### DPoP Proof JWT Structure and Requirements

#### JWT Header

The JWT header should contain the following parameters:

<table><thead><tr><th width="122.17578125">Parameter</th><th>Description</th><th>Data Type</th></tr></thead><tbody><tr><td><code>alg</code></td><td>The signature algorithm that you are using to sign this JWT</td><td><p>One of the following strings:</p><ul><li><code>ES256</code></li><li><code>ES384</code></li><li><code>ES512</code></li></ul></td></tr><tr><td><code>typ</code></td><td>The type of this JWT</td><td>Must be the string <code>dpop+jwt</code></td></tr><tr><td><code>jwk</code></td><td>The public key, in JSON Web Key format, that corresponds to the private key used to sign the JWT</td><td>Object in JSON Web Key format</td></tr></tbody></table>

<details>

<summary>Sample JWT header</summary>

```json
{
  "alg": "ES256",
  "typ": "dpop+jwt",
  "jwk": {
    "crv": "P-256",
    "kty": "EC",
    "x": "T59MDXABUkdP7DAvAnuZ3l-iLUylObl1v6DBqAp8LU0",
    "y": "D7NSWZW9_r2wZC10yobEiOgjoqDppoMdYSG3YV16QjU"
  }
}
```

</details>

#### JWT Payload

The JWT payload should contain the following claims:

<table><thead><tr><th width="88.7265625">Claim</th><th width="440.61328125">Description</th><th>Data type</th></tr></thead><tbody><tr><td><code>htm</code></td><td>The HTTP method of the request that you are making</td><td>Either the string <code>POST</code> or <code>GET</code></td></tr><tr><td><code>htu</code></td><td>The URL that you are making the request to.</td><td>URL</td></tr><tr><td><code>iat</code></td><td>The unix timestamp, in seconds, at which you generated this JWT.</td><td>This value must be a <a href="https://datatracker.ietf.org/doc/html/rfc7519#section-2"><code>NumericDate</code></a> type, representing seconds.</td></tr><tr><td><code>exp</code></td><td>The unix timestamp, in seconds, on or after which this JWT <strong>must not</strong> be accepted by us for processing.<br><br>Note also that this must be less than or equal to 2 minutes after <code>iat</code>.</td><td>This value must be a <a href="https://datatracker.ietf.org/doc/html/rfc7519#section-2"><code>NumericDate</code></a> type, representing seconds.</td></tr><tr><td><code>jti</code></td><td>A unique identifier for this token. This identifier must only be used once. You should generate a new <code>jti</code> value for every request</td><td>String</td></tr><tr><td><code>ath</code></td><td>Required only for the userinfo request. This should be the base64url-encoded SHA-256 hash of the access token.</td><td>A base64url-encoded string.</td></tr></tbody></table>

<details>

<summary>Sample JWT payload</summary>

```json
{
  "jti": "50ac59b2-a1e7-4bac-909b-68b692207b6c",
  "htm": "POST",
  "htu": "https://stg-id.singpass.gov.sg/fapi/par",
  "iat": 1771819829,
  "exp": 1771819949
}
```

</details>

### Signing and using the JWT

The JWT should be signed using your private DPoP key to form a JSON Web Signature (JWS) in compact serialisation format. This is a format where the three parts of the JWS (the header, the payload, and the signature), are base64url encoded and concatenated together, using a dot (`.`) as the separator.

The private key used to sign the JWT must correspond to the public key indicated in the `jwk` parameter in the JWT header.

This JWS should then be included in the `DPoP` request header when you are making requests that require DPoP.

```
DPoP: <your_signed_jwt>
```

### Validate Your DPoP Implementation&#x20;

&#x20;You can validate your DPoP proof JWT using this online validator tool:

[DPoP & Client Assertion Validator](https://client-assertion-dpop-validator.vercel.app/)

This tool helps you:

* Verify JWT structure and compact format
* Check required header parameters (alg, typ, jwk)
* Validate required payload claims
* Confirm signature validity
* Detect common implementation errors


---

# 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/technical-specifications/technical-concepts/demonstrating-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.
