How DPoP Works: A Guide to Proof of Possession for Web Tokens
Web authentication is a crucial aspect of any web application that involves user data and interactions. However, web authentication is also vulnerable to various attacks, such as replay attacks, phishing attacks, or token theft. These attacks can compromise the security and privacy of both the users and the web applications.
To prevent these attacks, a new technology called DPoP (Demonstrated Proof of Possession) has been proposed. DPoP is a way of binding web tokens to the client that requests them, so that only the legitimate client can use them. DPoP can enhance the security and privacy of web authentication by preventing token replay, token leakage, or token impersonation.
In this article, you will learn how DPoP works, how to implement it in your web applications, and what benefits it can bring to your security and privacy. You will also see some examples of DPoP in action and some challenges and limitations of DPoP. We’ll try to answer the following questions:
What is DPoP?
How does DPoP work?
How to implement DPoP in your web applications?
What are the benefits of DPoP?
What are the challenges and limitations of DPoP?
Why need a DPoP Token?
Let’s start it by asking what are the drawbacks of the current authentication/authorization flow? If you need to learn how a simple authentication/authorization system works, you can refer to this article.
In this article, we'll investigate why a simple authentication system might not work.
Let’s take an example to understand it. When a user wants to access a resource such as cute dog videos from the server (Resource Server), they have to provide a token or something that tells the server that this user is an authenticated user and is authorized to access the videos.
The way you get yourself authenticated is by providing your email and password and registering yourself with the server (Authorization Server). The server then sends you a token that you can use to communicate with it afterward.
The token you receive is a secret code that only the server can understand. You just have to send it back when the server asks for it. This way, you can avoid typing your email and password every time.
But what if the token that the server gave you is leaked? What if you mistakenly sent the token to one of your friends who now uses your token to watch dog videos?
It's a problem, isn't it? How will the server know whether the token is sent by you or your friend? All it knows is that it provided the token to the person who authenticated themselves with them by their password and email, and since only that person knows the password, it must be coming from them.
So, even though it was your friend who was using your token, the server thought it was you all the time. Poor server.
Can we protect this, somehow? Yes, there are multiple ways, and the first is to never share your token with anyone. Keep the token short-lived, such as 2 hrs, after which the token will no longer be deemed valid. The user has to authenticate themselves again with the server, and the server will provide them with the new token.
It will however irritate the user because they have to provide the credentials again and again, and they might not even come to your website again. So it's a tradeoff between the user experience and the security.
But let's not lose hope; another way to mitigate the misusage of the leaked token is to use the DPoP token. As the name implies, it gives the server additional information, telling them that they are the rightful owner of the token; that is why it is called Demonstrating Proof of Possession. Possession of what? Private Key!
The process involves some cryptographic jargon, so let's get away with that first.
DPoP involves Asymmetric cryptography*.*
Asymmetric cryptography involves public and private keys. These are nothing but random strings that are somehow related to each other by a mathematical function, however you cannot infer the private keys from public keys, not in thousand years.
As the name suggests, the private key must always be kept confidential; you don't reveal it, no matter what. Whereas the public key is like your bank account number, one can know it, but that doesn't mean they have access to your account. But, If they know your private key, they surely can.
How Asymmetric Cryptography Secures Your Data and Communication?
Let's say we both are secret agents, and I want to convey to you some information on where to meet. I sent you a message: Meet me at Bellandur around 2:00 PM.
But, here's a catch: other people can intercept (man in the middle) this message and alter it. Let's say someone changes the message to Meet me at Koramangala around 1:00 PM.
How will you know that the message has not been altered?
We can't! without the help of cryptography.
Let's introduce the two keys we discussed and see if they can help us somehow.
For this, I will use real key pairs to demonstrate the process. PS: I used Blockchain Demo: Public / Private Keys & Signing(andersbrownworth.com) to generate the key and sign the message. I used the random private key that they provided and its corresponding public key.
It doesn't matter actually which algo we use to generate it.
Private Key
3982784195248803137024316195121899530329082404317191097441586000053750802
6761
Public Key
042c6f260e108ff036904f5ad974f11fa1ea8aca1f324675ea44c82b5b7d68dd228c84ea0
d95ba8f4c2078207e4f8e4e2650bf538a405e436cc9d93f52bfdb12cf
Once the keys are generated, you first sign the message, which is Meet me at Bellandur around 2:00 PM with your private key. This will give you a signature.
Signature
304402207d0cf38da791274f96fdd66d0f349c264291810334c16e00440d7234ffbc198702
201fee48eefc6512c6a1c5891ece44ed3dc525a733d10c6319a35dd8ec7c4cbba2
This will result in the complete info that I can now send to you, knowing fully well that nobody can alter it without you knowing it.
Message:
Meet me at Bellandur around 2:00 PM
Public Key:
042c6f260e108ff036904f5ad974f11fa1ea8aca1f324675ea44c82b5b7d68dd228c84ea
0d95ba8f4c2078207e4f8e4e2650bf538a405e436cc9d93f52bfdb12cf
Signature:
304402207d0cf38da791274f96fdd66d0f349c264291810334c16e00440d7234ffbc1987
02201fee48eefc6512c6a1c5891ece44ed3dc525a733d10c6319a35dd8ec7c4cbba2
After receiving the info, you want to verify if it was me who actually sent this to you. For this, you'll take the public key that I sent, the message, and the signature and apply the mathematical function, and it will produce a yes or a no.
If the answer is yes, then the signature is valid, and the message has not been altered and is intact. If it is not, someone might have changed it, so we better cancel the plan.
To go into what mathematical function to apply is not the scope of the article, but rest assured, you can verify the signature and come up with a 100% surety of whether the message has been altered or not.
Again, you can use the abovementioned website to play with the tools.
We would know if someone would have changed the message, even a single dot.
Now, having this knowledge, we can proceed with the basics of DPoP.
For this context, assume there are three actors:
The Client
The Authorization Server (or AS) (the one who issues tokens)
The Resource Server (or RS) (the one where you can watch dog videos)
Alright, earlier, without DPoP, here are the steps you would take to watch the dog videos:
The Usual Way
Login / Sign up with the Authorization Server by submitting your email and password.
If you are a first-time user, you'll be thrown a hurdle, such as opening up your email and verifying the email, or in case of a phone number, you might be asked to provide the OTP.
If you are already a registered user, the server will check the credentials you passed with the one in the database. Once it verifies its authenticity, you'll be authenticated and will be provided a bearer token.
It is named bearer because anyone who possesses or bears the token can use it to access the protected resource without having to prove their identity because they already did it.
Now, you can ask the Resource Server to give the dog videos by providing your bearer token.
The Resource Server will check that you have got the bearer token and it is valid. It will then send you loads of Dog videos.
But if someone gets a hold of your token, they can ask the Resource Server for the resources without having to prove anything since a bearer token means they already have been authenticated.
This is where DPoP comes into the picture. But things change a lot.
The DPoP Way
You first generate a key pair (public/private) key.
You then create a JWT token. This is also called DPoP Proof JWT, and it is sent to the authorization server to get an access token. More on that later.
The JWT Token that you create consists of three parts:
JWT Header
JWT Payload
Signature
JWT Header
The header contains the crucial information, such as:
The type of algorithm used to generate the key pairs (ES256).
What kind of JWT is it? It is dpop+jwt
The public key itself is in the form of JWK. A JWK is a JSON data structure that represents a cryptographic key. It has the following attributes:
kty
(key type): this parameter identifies the cryptographic algorithm family used within the key, such as EC (Elliptic Curve).x, y
the coordinate on the elliptic curve. (Out of scope for this article)crv
: the curve used with the key. (Out of scope).
{
"typ":"dpop+jwt",
"alg":"ES256",
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
JWT Payload
The payload contains.
jti
claim, this is a unique identifier.htm
claim, the HTTP method used.htu
claim, the URL that you are sending your request to. In our case, we are sending the request to the authorization server.iat
claim contains the timestamp when you issued the JWT token.
{
"jti":"-MwC4Ehc6acd2lT1",
"htm":"POST",
"htu":"https://your.authorization.server/dpop/token",
"iat":1695035425
}
JWT Signature
The signature is the last part of the JWT, and it is used to verify the integrity and authenticity of the JWT. It is signed using the private key of the client.
2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg4PtFLbdLXiOSsX0x7NVY-
FNyJK70nfbV37xRZT3Lg
The signature is then base64url encoded and appended to the JWT, separated by another dot.
The final DPoP proof JWT looks like this:
eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDI
iwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCRn
MiLCJ5IjoiOVZFNGpmX09rX286NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1J
EQSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHR
tIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2Vu
IiwiaWF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqR
MUvwnQg4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg
Our next step is to build the request to be sent to the Authorization Server. We have so far completed the JWT Token creation. Here is an example of what a request might look like:
POST /token HTTP/1.1
Host: your.authorization.server.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\\
VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\\
nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\\
QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\\
oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\\
WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\\
4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg
grant_type=authorization_code\\
&client_id=s6BhdRkqt\\
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb\\
&code_verifier=bEaL42izcC-o-xBk0K2vuJ6U-y1p9r_wW2dFWIWgjz-
The Authorization Server
When the authorization server receives the request, it looks for the DPoP
header field sent by the client. It extracts the public key, payload, and header and uses the public key to verify the signature. If the verification is successful, it means the client who sent this request is the owner of the private key, and this public key belongs to them. In the same way, we ensured that the message was valid if the signature was verified in the case of our two agents.
After verifying, the Authorization Server issues a token of type DPoP. This means that the authorization server returns an access token (notice it is not called a bearer token) and, optionally, a refresh token that is bound to the public key of the client.
The token type is indicated by a "typ" parameter in the token response, which has the value "DPoP". For example, a token response may look like this:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0xIn0.eyJzdWIiOiJib2IiLCJhdWQiOiJodHRwczovL3Jlc291cmNlLmV4YW1wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly9hdXRob3JpemF0aW9uLXNlcnZlci5leGFtcGxlLmNvbSIsImV4cCI6MTYyMjMwMjQwMCwiaWF0IjoxNjIyMzAxODAwLCJqdGkiOiJhYmNkLTEyMyIsImNuZiI6eyJqa3QiOiJIM0ZBbkVnTmVEbkZiTFdIaDNjUjNCNjN3STJVMGhtMFpUdUlWXzhJOEVVIn19.UMg7r2fQ8B7tC8sQkE8vqf7eO9xhFbHr4fQnqKsQwqg",
"token_type": "DPoP",
"expires_in": 3600
}
The access token generated contains the following payload:
{
"sub": "bob",
"aud": "https://resource.example.com",
"iss": "https://your.authorization.server.com",
"exp": 1622302400,
"iat": 1622301800,
"jti": "abcd-123",
"cnf": {
"jkt": "H3FAnEgNeDnFbLWHh3cR3B63wI2U0hm0ZTuIV_8I8EU"
}
}
Please note there is a claim called cnf
. This is the hash of our public key sent to the Authorization Server.
The cnf claim is a way of linking a token to a key. Here, we have linked our access token with the public key sent by the client.
The thumbprint is computed using the SHA-256 algorithm defined by RFC 7638. For example, if the public key in the DPoP proof JWT is:
{
"kty": "RSA",
"n": "o5Fiw7GSdTDrO61ivks7KM2M7bLar4HF9DWLcIRDGcQqNu0aRMkWLD4QEBtqkyV8Uu30WZ4g8sZxgSGLVoSH9JGc270vWqtA0fYx7AhFi1JPHM-v3Kz3PtLHCIXTRFi-Cj-uDNn31RMduMVevtjmuPz99_qvQU4lDGhQsyAjONNEjYQ5wJp_iYVYPXXRpP3rGg2avoTrsvtFzEABecmIKWGh556M7qSFwdboIUKG-Q6DdBYD9aq3tm0A8JiFATA3RONVF8dSIPl1dfUkwRsosZI2Fr-OT51x6J5f0Kz8J6DUj_UHr0ecwtn25sLZHEN-fCxZ1LeEK-ZeUgIrxZLagw",
"e": "AQAB",
"kid": "HjFAbEgNeDnFbLWHh3cR3B63wI2U0xm0ZTuIV_8I8EU"
}
Then, the thumbprint will be:
H3FAnEgNeDnFbLWHh3cR3B63wI2U0xm0ZTuIV_8I8EU
And the cnf
claim in the access token is:
"cnf": { "jkt": "H3FAnEgNeDnFbLWHh3cR3B63wI2U0xm0ZTuIV_8I8EU" }
Once we have the access token, we can request the dog videos from the Resource Server (or RS).
Here's how:
- You first create a JWT token similar to what we created before sending it to the Authorization Server. But this time, the payload will be different;
htu
will be of the Resource Server instead of the Authorization Server. Also, thehtm
will depend on what kind of resource you are trying to access; since you are asking for dog videos, most probably, it will be GET.
{
"jti": "-NMwJ4Ehc6acd2lT1",
"htm": "GET",
"htu": "https://docstore.traefik.plat.phonepe.com/get/videos/12342",
"iat": 1695060322
}
- The header of the JWT token will contain the public key that we generated the first time.
{
"typ":"dpop+jwt",
"alg":"ES256",
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
- After forming the token, sign it with your private key to generate a signature.
z9tyS3pDAgdHgzAz9kV6gMsjXme3KqvEjZm-FbXIGe3JfojvZvgYEWHQ72Munq2az8U
XokzrJ2ZDIsYaAEKOzA
- The final DPoP Proof token will look something like this
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiItTk13SjRFaGM2YWNkMmx
UMSIsImh0bSI6IkdFVCIsImh0dSI6Imh0dHBzOi8vZG9jc3RvcmUudHJhZWZpay5wbGF
0LnBob25lcGUuY29tL2dldC92aWRlb3MvMTIzNDIiLCJpYXQiOjE2OTUwNjAzMjJ9.z9
tyS3pDAgdHgzAz9kV6gMsjXme3KqvEjZm-FbXIGe3JfojvZvgYEWHQ72Munq2az8UXok
zrJ2ZDIsYaAEKOzA
- Now, all we need is to create a Request.
curl -v -X GET \\
--header 'Accept: application/json' \\
--header 'Content-Type: application/json' \\
--header 'Authorization: DPoP eyJraWQiOiJRVX.....wt7oSakPDUg' \\
--header 'DPoP: eyJ0eXAiOiJkcG9w.....H8-u9gaK2-oIj8ipg' \\
"https://docstore.traefik.plat.phonepe.com/get/videos/12342"
Note: we are sending both the access token we got from the Authorization Server and the one we created ourselves.
The access token is sent in the Authorization Header, and our Proof is sent in the DPoP header.
Resource Server: Validate the access token and DPoP header
Once the Resource server receives your request, it validates the headers sent by you.
First, it verifies the signature; if it is invalid, it drops the request; otherwise, it checks for the access token to see whether it contains the
cnf
claim.After this, it compares the access token's jkt with the DPoP header's public key.
Once that is confirmed, It returns you the Dog Videos.
Conclusion
DPoP is a promising technology that can enhance the security and privacy of web authentication. By binding web tokens to the client that requests them, DPoP can prevent various attacks that exploit web tokens. DPoP can also enable more granular and flexible access control for web resources.
However, DPoP is not a silver bullet for web authentication. It still has some challenges and limitations, such as compatibility issues, performance overhead, or key management. Therefore, DPoP should be used with caution and in combination with other security measures.
If you want to learn more about DPoP or try it out yourself, you can check out these references:
References
Subscribe to my newsletter
Read articles from Kishan Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Kishan Kumar
Kishan Kumar
I am a Software Engineer at PhonePe.