Logo
  • Home
  • Overview packages
  • Concepts and terminology

Tutorials

  • Require authentication by default
  • Handling token expiration
  • Security middlewares overview
  • Server to server communication
    • Overview
    • Client credentials token request from a Web host
    • Manual client credential token request
    • Service calling multiple external APIs

Code lab

  • Client credentials flow (server to server)
    • Using IHttpClientFactory and Duende AccessToken Management
    • Bearer token request using client assertion
    • Bearer token request using shared secret
    • DPoP token request
    • Manual token request with Duende IdentityModel
FHI authentication and authorization extensions
  • Code lab
  • Client credentials flow (server to server)
  • DPoP token request
  • Edit on GitHub

DPoP token request¶

This example demonstrates how to manually request a DPoP token using the OAuth 2.0 client credentials flow. The code sample demostrates how to request an access token from an OAuth 2.0 /token endpoint using DPoP (Demonstration of Proof of Possession), including support for nonce binding to enhance security.

For a detailed explanation of the code flow, see the tutorial.

Note! Be careful with new HttpClient(), it is only for demo purposes.

In [ ]:
Copied!
#r "nuget: Fhi.Authentication.Extensions, 1.0.0"
#r "nuget: Duende.IdentityModel, 7.0.0"
#r "nuget: Microsoft.IdentityModel.Tokens, 8.9.0"

using System;
using System.Net.Http;
using System.Collections.Generic;
using Fhi.Authentication.Tokens;
using Duende.IdentityModel;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Text.Json;

var tokenEndpoint = "https://demo.duendesoftware.com/connect/token";
var clientId = "m2m.dpop.nonce";
var scope = "api";
var clientSecret = "secret";

var dpopKey = JwkGenerator.GenerateRsaJwk();
Console.WriteLine($"DPoP Public Key: {dpopKey.PublicKey}");
Console.WriteLine($"DPoP Private Key: {dpopKey.PrivateKey}");

/************************************************************************
* 1. Request token to get nonce
*************************************************************************/
var nonceRequest = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint)
{
    Content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("grant_type", "client_credentials"),
        new KeyValuePair<string, string>("client_id", clientId),
        new KeyValuePair<string, string>("client_secret", clientSecret),
        new KeyValuePair<string, string>("scope", scope)
    })
};
var dpopProof = TokenHandlers.CreateDPoPProof(
    dpopKey,
    new JwtPayload
        {
            [JwtClaimTypes.JwtId] = Guid.NewGuid().ToString(),
            [JwtClaimTypes.DPoPHttpMethod] = HttpMethod.Post.Method.ToString(),
            [JwtClaimTypes.DPoPHttpUrl] = tokenEndpoint,
            [JwtClaimTypes.IssuedAt] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
        });
nonceRequest.Headers.Add("DPoP", dpopProof);
await LogRequest(nonceRequest);

var client = new HttpClient();
var nonceResponse = await client.SendAsync(nonceRequest);
await LogResponse(nonceResponse);

/************************************************************************
* 2. Request token with nonce in DPoP proof
*************************************************************************/
var dpopNonce = nonceResponse.Headers.TryGetValues("DPoP-Nonce", out var nonceValues) ? string.Join(",", nonceValues) : null;
var dpopProofWithNonce = TokenHandlers.CreateDPoPProof(
    dpopKey,
    new JwtPayload
        {
            [JwtClaimTypes.JwtId] = Guid.NewGuid().ToString(),
            [JwtClaimTypes.DPoPHttpMethod] = HttpMethod.Post.Method.ToString(),
            [JwtClaimTypes.DPoPHttpUrl] = tokenEndpoint,
            [JwtClaimTypes.IssuedAt] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
            [JwtClaimTypes.Nonce] = dpopNonce
        });

var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint)
{
    Content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("grant_type", "client_credentials"),
        new KeyValuePair<string, string>("client_id", clientId),
        new KeyValuePair<string, string>("client_secret", clientSecret),
        new KeyValuePair<string, string>("scope", scope)
    })
};
tokenRequest.Headers.Add("DPoP", dpopProofWithNonce);
await LogRequest(tokenRequest);

var tokenResponse = await client.SendAsync(tokenRequest);
await LogResponse(tokenResponse);

public static class TokenHandlers
{
    public static string CreateDPoPProof(JwkKeyPair key, JwtPayload payload)
    {
        var securityKey = new JsonWebKey(key.PrivateKey);
        var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);
        var jwkDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(key.PublicKey);
        var jwtHeader = new JwtHeader(signingCredentials)
        {
            [JwtClaimTypes.TokenType] = "dpop+jwt",
            [JwtClaimTypes.JsonWebKey] = jwkDict,
        };
        var jwt = new JwtSecurityToken(jwtHeader, payload);
        return new JwtSecurityTokenHandler().WriteToken(jwt);
    }
}
#r "nuget: Fhi.Authentication.Extensions, 1.0.0" #r "nuget: Duende.IdentityModel, 7.0.0" #r "nuget: Microsoft.IdentityModel.Tokens, 8.9.0" using System; using System.Net.Http; using System.Collections.Generic; using Fhi.Authentication.Tokens; using Duende.IdentityModel; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Text.Json; var tokenEndpoint = "https://demo.duendesoftware.com/connect/token"; var clientId = "m2m.dpop.nonce"; var scope = "api"; var clientSecret = "secret"; var dpopKey = JwkGenerator.GenerateRsaJwk(); Console.WriteLine($"DPoP Public Key: {dpopKey.PublicKey}"); Console.WriteLine($"DPoP Private Key: {dpopKey.PrivateKey}"); /************************************************************************ * 1. Request token to get nonce *************************************************************************/ var nonceRequest = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint) { Content = new FormUrlEncodedContent(new[] { new KeyValuePair("grant_type", "client_credentials"), new KeyValuePair("client_id", clientId), new KeyValuePair("client_secret", clientSecret), new KeyValuePair("scope", scope) }) }; var dpopProof = TokenHandlers.CreateDPoPProof( dpopKey, new JwtPayload { [JwtClaimTypes.JwtId] = Guid.NewGuid().ToString(), [JwtClaimTypes.DPoPHttpMethod] = HttpMethod.Post.Method.ToString(), [JwtClaimTypes.DPoPHttpUrl] = tokenEndpoint, [JwtClaimTypes.IssuedAt] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), }); nonceRequest.Headers.Add("DPoP", dpopProof); await LogRequest(nonceRequest); var client = new HttpClient(); var nonceResponse = await client.SendAsync(nonceRequest); await LogResponse(nonceResponse); /************************************************************************ * 2. Request token with nonce in DPoP proof *************************************************************************/ var dpopNonce = nonceResponse.Headers.TryGetValues("DPoP-Nonce", out var nonceValues) ? string.Join(",", nonceValues) : null; var dpopProofWithNonce = TokenHandlers.CreateDPoPProof( dpopKey, new JwtPayload { [JwtClaimTypes.JwtId] = Guid.NewGuid().ToString(), [JwtClaimTypes.DPoPHttpMethod] = HttpMethod.Post.Method.ToString(), [JwtClaimTypes.DPoPHttpUrl] = tokenEndpoint, [JwtClaimTypes.IssuedAt] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), [JwtClaimTypes.Nonce] = dpopNonce }); var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenEndpoint) { Content = new FormUrlEncodedContent(new[] { new KeyValuePair("grant_type", "client_credentials"), new KeyValuePair("client_id", clientId), new KeyValuePair("client_secret", clientSecret), new KeyValuePair("scope", scope) }) }; tokenRequest.Headers.Add("DPoP", dpopProofWithNonce); await LogRequest(tokenRequest); var tokenResponse = await client.SendAsync(tokenRequest); await LogResponse(tokenResponse); public static class TokenHandlers { public static string CreateDPoPProof(JwkKeyPair key, JwtPayload payload) { var securityKey = new JsonWebKey(key.PrivateKey); var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256); var jwkDict = System.Text.Json.JsonSerializer.Deserialize>(key.PublicKey); var jwtHeader = new JwtHeader(signingCredentials) { [JwtClaimTypes.TokenType] = "dpop+jwt", [JwtClaimTypes.JsonWebKey] = jwkDict, }; var jwt = new JwtSecurityToken(jwtHeader, payload); return new JwtSecurityTokenHandler().WriteToken(jwt); } }
Previous Next

Built with MkDocs using a theme provided by Read the Docs.
GitHub « Previous Next »