Jesse Brands
Jesse Brands

Reputation: 2877

Microsoft.Identity.Web and ASP.NET Core SignalR JWT authentication

I am using ASP.NET Core to make a web application that also uses SignalR Core to provide real time functionality. I use Azure AD B2C for user management. I have successfully used Microsoft.Identity.Web (https://github.com/AzureAD/microsoft-identity-web) to secure my API endpoints using tokens generated by Azure AD B2C.

I would like to do the same for my SignalR Core hubs. The documentation reads to add the appropriate annotation to your hubs/methods, which I have done. SignalR's client side library adds the access token as a query parameter which must be extracted and added to the context manually in the configuration of your ASP.NET core application, like so.

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                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/chat")))
                {
                    // Read the token out of the query string
                    context.Token = accessToken;
                }
                return Task.CompletedTask;
            }
        };
    });

However, this seems to be incompatible with the configuration supplied by Microsoft.Identity.Web, here:

        services
            .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAdB2C"));

How can I make SignalR work with Microsoft.Identity.Web?

Upvotes: 7

Views: 2222

Answers (2)

eltoncezar
eltoncezar

Reputation: 301

That should do it:

services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(configuration);

services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    Func<MessageReceivedContext, Task> existingOnMessageReceivedHandler = options.Events.OnMessageReceived;
    options.Events.OnMessageReceived = async context =>
    {
      await existingOnMessageReceivedHandler(context);

      StringValues accessToken = context.Request.Query["access_token"];
      PathString path = context.HttpContext.Request.Path;

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

Instead of adding a JwtBearer, you can configure the JwtBearerOptions object this way.

Adapted from this documentation: https://github.com/AzureAD/microsoft-identity-web/wiki/customization

Upvotes: 10

Jenny
Jenny

Reputation: 1229

You can use Visual Studio to set up the SignalR connection, and then just add this line in startup.cs (VS might add it automatically)

services.AddSignalR().AddAzureSignalR();

This dev sample has SignalR set up, just the connection string is missing, but might give you an idea of what to do. Most of this was done automatically with VS. If you have issues setting it up, please open an issue in the repo. thanks.

Upvotes: 0

Related Questions