0

I have created the default ASP.NET Core Web App project using Visual Studio 2022 and .Net 6.

As the authentication type I have chosen Microsoft identify platform.

Example app settings

How do I get hold of the JWT that AzureAD generates for me as part of OpenID Connect?

I have changed the authentication service in the program.cs to use the option SaveTokens as follows:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        builder.Configuration.Bind("AzureAd", options);
        options.SaveTokens = true;
    });

builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy.
    options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapControllers();

app.Run();

I want access to the JWT tokens so I can pass them to a bespoke service we have. I do not want regenerate them, I want the tokens that Microsoft have signed.

To test getting hold of them I have tried GetTokenAsync from the Microsoft.AspNetCore.Authentication extensions like so (in Index.cshtml)

@page
@using Microsoft.AspNetCore.Authentication
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <p>Access Token: @await HttpContext.GetTokenAsync("OpenIdConnect","access_token")</p>
    <p>Refresh Token: @await HttpContext.GetTokenAsync("OpenIdConnect", "refresh_token")</p>
</div>

But alas - I get nulls back. Any ideas? Result below:

Example of web page sans JWT information

Jonny
  • 796
  • 2
  • 10
  • 23
  • Not sure how it works, but is it possible the token is in an HttpOnly browser cookie? – DavidG Nov 11 '21 at 17:33
  • Why do you want this anyway? SSO? – CodeCaster Nov 11 '21 at 17:44
  • @CodeCaster - it is a good question! I have a custom built backend service that can take the JWT, make sure it is trusted correctly (check it by the certificates in the OpenID connect metadata stuff) and use the user name. – Jonny Nov 11 '21 at 17:51
  • @DavidG - yeh, but it I think it shouldn't matter because my code is running server side. It is interesting though because I can't see anything that looks particularly JWT like in any of the response cookies. – Jonny Nov 11 '21 at 17:51

1 Answers1

1

Well I'm none the wiser why the original SaveTokens method doesn't work but here is a way to make it work:

It's not quite to same but gets me what I need. Hook into the event OnTokenValidated and then save it explicitly on the identity as follows (in program.cs):

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        builder.Configuration.Bind("AzureAd", options);
        options.Events.OnTokenValidated = context =>
        {
            var accessToken = context.SecurityToken as JwtSecurityToken;
           

            if (accessToken != null)
            {
                var identity = context.Principal.Identity as ClaimsIdentity;
                if (identity != null)
                {
                    identity.AddClaim(new Claim("access_token", accessToken.RawData));
                }
            }

            return Task.FromResult(0);
        };

    });

And then access it from the user.identity - following just for testing (in Index.cshtml):

<p>Access Token: @((User.Identity as ClaimsIdentity).Claims.Where( c => c.Type == "access_token").FirstOrDefault().Value)</p>
Jonny
  • 796
  • 2
  • 10
  • 23