Skip to content

Proof Of Possession (PoP) tokens

Jean-Marc Prieur edited this page Apr 25, 2021 · 28 revisions

This is a new feature introduced in MSAL 4.8. Currently it is supported only for confidential client flows.

Proof of Possession Access Tokens

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;

//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"})
      .WithProofOfPosession(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 cryptograpgic 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 symetric 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

Future work

We await questions and feedback on this feature. The next steps for this are:

  • allow PoP tokens on other platforms, .NET Core in particular
  • protect the Refresh Tokens with the same technique, i.e. PoP refresh tokens.

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