Aspnetcore.docs: SignalR Core Auth - Token in Query String section does not address AddIdentityServerJwt()

Created on 12 Apr 2020  Â·  4Comments  Â·  Source: dotnet/AspNetCore.Docs

The Token in Query String section addresses the case where AddJwtBearer() is called directly:

 services.AddAuthentication()
        .AddJwtBearer(options =>//options from documentation);

It does not cover the Identity Server case where AddIdentityServerJwt() is used instead, which is the default for Blazor WebAssembly apps scaffolded with authentication.

 services.AddAuthentication()
        .AddIdentityServerJwt();

In this case, calling AddJwtBearer after AddIdentityServerJwt does not work:

// this does not work
services.AddAuthentication()
                .AddIdentityServerJwt()
                .AddJwtBearer(options =>//options from documentation);

Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

P1 SignalR Source - Docs.ms doc-enhancement

Most helpful comment

I was able to get it working using a PostConfigureOptions service:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;

namespace App.Server.Services
{
    public class ConfigureJwtBearerOptions : IPostConfigureOptions<JwtBearerOptions>
    {
        public void PostConfigure(string name, JwtBearerOptions options)
        {
            // save the original OnMessageReceived event
            var originalOnMessageReceived = options.Events.OnMessageReceived;

            options.Events.OnMessageReceived = async context =>
            {
                // call the original OnMessageReceived event
                await originalOnMessageReceived(context);

                if (string.IsNullOrEmpty(context.Token))
                {
                    // attempt to read the access token from the query string
                    var accessToken = context.Request.Query["access_token"];

                    // If the request is for our hub...
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
                    {
                        // Read the token out of the query string
                        context.Token = accessToken;
                    }
                }
            };
        }
    }
}

Startup.cs configuration:

            services.AddAuthentication()
                .AddIdentityServerJwt();
            services.TryAddEnumerable(
                ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>());

All 4 comments

@guardrex here is another one related to IS that I encountered using Blazor WebAssembly with SignalR.

Note that WebSockets will not pass access tokens in the query string the C# SignalR client running in the browser until https://github.com/dotnet/aspnetcore/pull/20466 is merged. I have a workaround to pass the access token in the query string that I have been testing this with though.

I was able to get it working using a PostConfigureOptions service:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;

namespace App.Server.Services
{
    public class ConfigureJwtBearerOptions : IPostConfigureOptions<JwtBearerOptions>
    {
        public void PostConfigure(string name, JwtBearerOptions options)
        {
            // save the original OnMessageReceived event
            var originalOnMessageReceived = options.Events.OnMessageReceived;

            options.Events.OnMessageReceived = async context =>
            {
                // call the original OnMessageReceived event
                await originalOnMessageReceived(context);

                if (string.IsNullOrEmpty(context.Token))
                {
                    // attempt to read the access token from the query string
                    var accessToken = context.Request.Query["access_token"];

                    // If the request is for our hub...
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
                    {
                        // Read the token out of the query string
                        context.Token = accessToken;
                    }
                }
            };
        }
    }
}

Startup.cs configuration:

            services.AddAuthentication()
                .AddIdentityServerJwt();
            services.TryAddEnumerable(
                ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>());

@BrennanConroy Do we need to cover anything in this topic given https://github.com/dotnet/aspnetcore/pull/20466?

Since https://docs.microsoft.com/aspnet/core/tutorials/signalr-blazor-webassembly is a tutorial, this information would have to go in the SignalR topic if covered.

Do we need to cover anything in this topic given dotnet/aspnetcore#20466?

That bug is a bug in a preview product (blazor webassembly) and will be fixed by release. So I'm not sure any docs need to be written for it.

As for AddIdentityServerJwt, something should be done there as it looks un-obvious how to handle the access_token query string.

Was this page helpful?
0 / 5 - 0 ratings