Skip to content

Proof Of Possession (PoP) tokens

Travis Walker edited this page Jun 13, 2022 · 28 revisions

Proof of Possession Confidential Clients

Bearer tokens are the norm in modern identity flows, however they are vulnerable to being stolen and used to access a protected resource.

Proof of Possession (PoP) tokens mitigate this threat via 2 mechanisms:

  • they are bound to the user / machine that wants to access a protected resource, via a public / private key pair
  • they are bound to the protected resource itself, i.e. a token that is used to access GET https://contoso.com/transactions cannot be used to access GET https://contoso.com/tranfer/100

For more details, see RFC 7800

Code sample

Sample

See the full code sample show casing a daemon app using AcquireTokenForClient with Pop to call an API protected with Pop: https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/4-Call-OwnApi-Pop

Code snippet

//The PoP token will be bound to this user / machine and to `GET https://www.contoso.com/tranfers` (the query params are not bound)
//Request URI is required in the PopAuthenticationConfiguration constructor
PopAuthenticationConfiguration popConfig = new PopAuthenticationConfiguration(new Uri("https://www.contoso.com/tranfers?user=me"));

//HttpMethod is optional
popConfig.HttpMethod = HttpMethod.Get;

// Server nonce (optional)
// popConfig.Nonce = 

//PopCryptoProvider is optional. Do not set to use MSAL'S internal implementation.
popConfig.PopCryptoProvider = new ECDCertificatePopCryptoProvider();
          
var cca = ConfidentialClientApplicationBuilder.Create(CLIENT_ID)
    .WithExperimentalFeatures()     // Currently POP is marked as an experimental feature
    .Build();


result = await cca
      .AcquireTokenForClient (new[] { "scope"})
      .WithProofOfPossession(popConfig)
      .ExecuteAsync()
      .ConfigureAwait(false);

//The PoP token will be available on the AuthenticationResult returned form the acquireToken call
result.AccessToken;

//To create the auth header
var authHeader = new AuthenticationHeaderValue(result.TokenType, result.AccessToken);

How does MSAL manage the keys

An RSA key pair of length 2048 is generated by MSAL and stored in memory which will be cycled every 8 hours. For more details please inspect the code here and here

Can I use POP?

To use PoP, you first need to protect an API with PoP. More details in the wiki.

If you are writing a new API, you protected using PoP exclusively and require clients to generate PoP tokens. If you are upgrading an existing API, consider supporting both Bearer and PoP tokens for a while, to allow clients to migrate. MSAL supports requesting both Bearer and PoP tokens for the same resource.

Bring your own key

The POP feature in MSAL allows users to provide their own key management for additional control over cryptographic operations in POP. The interface is An abstraction over an the asymmetric key operations needed by POP, that encapsulates a pair of public and private keys and some typical crypto operations. All symmetric operations are SHA256.

Important: The 2 properties and the sign method on this interface will be called at different times but MUST return details of the same private / public key pair, i.e. do not change to a different key pair mid way. Best to have this class immutable. Ideally there should be a single public / private key pair associated with a machine, so implementers of this interface should consider exposing a singleton. Please click the links below for more information.

IPoPCryptoProvider Interface

Example RSA key implementation

Example ECD key implementation

Proof of Possession for Public Clients

POP tokens on public client flows can be achieved with the use of the new preview WAM Broker (See Here) on windows. Contrary to the confidential client flow, it is not possible to provide your own key to sign the POP token.

In order to utilize the new broker to perform POP, see the code snippet below.

Code Snippet

using Microsoft.Identity.Client.Broker; //Required for the use of the preview broker

//The PoP token will be bound to this user / machine and to `GET https://www.contoso.com/tranfers` (the query params are not bound)
//the nonce is a requirement in this case and needs to be acquired from the resource before using this api.

// Server nonce is required
string nonce = "nonce";

//HttpMethod is optional
HttpMethod method = HttpMethod.Get;

//Request URI
Uri requestUri = new Uri("https://www.contoso.com/tranfers?user=me");
          
var pca = PublicClientApplicationBuilder.Create(CLIENT_ID)
    .WithExperimentalFeatures()     // Currently POP is marked as an experimental feature
    .WithBrokerPreview()  //Enables the use of broker on public clients only.
    .Build();

//Interactive Request
AuthenticationResult result = await pca
      .AcquireTokenInteractive(new[] { "scope"})
      .WithProofOfPossession(nonce, method, requestUri)
      .ExecuteAsync()
      .ConfigureAwait(false);

//The PoP token will be available on the AuthenticationResult returned form the acquireToken call
result.AccessToken;

//To create the auth header
var authHeader = new AuthenticationHeaderValue(result.TokenType, result.AccessToken);

//Silent Request
var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);
var result = await pca.AcquireTokenSilent(new[] { "scope"}, accounts.FirstOrDefault())
       .WithProofOfPossession(nonce, method, requestUri)
       .ExecuteAsync()
       .ConfigureAwait(false);

Getting started with MSAL.NET

Acquiring tokens

Desktop/Mobile apps

Web Apps / Web APIs / daemon apps

Advanced topics

News

FAQ

Other resources

Clone this wiki locally