title: signalr core (2.1) JWT authentication hub/negotiate 401 Unauthorized
body: <p>so I have a .net core (2.1) API that uses JWT tokens for authentication.  I can login and make authenticated calls successfully.</p>
  
  <p>I am using React (16.6.3) for the client, which getting a JWT code and making authenticated calls to the API works.</p>
  
  <p>I am trying to add signalr hubs to the site.  If I do not put an [Authorize] attribute on the hub class. I can connect, send and receive messages (its a basic chathub at the moment).</p>
  
  <p>when I add the [Authorize] attribute to the class, the React app will make an HttpPost to <code>example.com/hubs/chat/negotiate</code> .  I would get a <code>401</code> status code.  the <code>Authorization: Bearer abc.....</code> header would be passed up.</p>
  
  <p>To build the hub in React I use:</p>
  
  <pre><code>const hubConn = new signalR.HubConnectionBuilder()
              .withUrl(`${baseUrl}/hubs/chat`, { accessTokenFactory: () =&gt; jwt })
              .configureLogging(signalR.LogLevel.Information)
              .build();
  </code></pre>
  
  <p>where the <code>jwt</code> variable is the token.</p>
  
  <p>I have some setup for the authentication:</p>
  
  <pre><code>services.AddAuthentication(a =&gt;
  {
      a.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
      a.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  })
  .AddJwtBearer(options =&gt;
  {
      options.SaveToken = false;
      options.Audience = jwtAudience;
  
  options.TokenValidationParameters = new TokenValidationParameters
  {
      ValidateIssuer = true,
      ValidateAudience = true,
      ValidateLifetime = true,
      ValidateIssuerSigningKey = true,
      ValidIssuer = jwtIssuer,
      ValidAudience = jwtAudience,
      RequireExpirationTime = true,
      IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtKey)),
  
  };
  
  // We have to hook the OnMessageReceived event in order to
  // allow the JWT authentication handler to read the access
  // token from the query string when a WebSocket or 
  // Server-Sent Events request comes in.
  options.Events = new JwtBearerEvents
  {
      OnMessageReceived = context =&gt;
      {
          var accessToken = context.Request.Query["access_token"];
          var authToken = context.Request.Headers["Authorization"].ToString();
  
          var token = !string.IsNullOrEmpty(accessToken) ? accessToken.ToString() : !string.IsNullOrEmpty(authToken) ?  authToken.Substring(7) : String.Empty;
  
          var path = context.HttpContext.Request.Path;
  
          // If the request is for our hub...
          if (!string.IsNullOrEmpty(token) &amp;&amp; path.StartsWithSegments("/hubs"))
          {
              // Read the token out of the query string
              context.Token = token;
          }
          return Task.CompletedTask;
      }                    
  };
  </code></pre>
  
  <p>});</p>
  
  <p>the <code>OnMessageReceived</code> event does get hit and <code>context.Token</code> does get set to the JWT Token.</p>
  
  <p>I can't figure out what I am doing wrong to be able to make authenticated calls for signalr core.</p>
  
  <hr>
  
  <p><strong>solution</strong></p>
  
  <p>I updated my code to use 2.2 (not sure if this was actually required).</p>
  
  <p>so I spent some time looking at the source code, and the examples within:</p>
  
  <p><a href="https://github.com/aspnet/AspNetCore" rel="noreferrer">https://github.com/aspnet/AspNetCore</a></p>
  
  <p>I had a Signalr CORS issue which was solved with:</p>
  
  <pre><code>services.AddCors(options =&gt;
          {
              options.AddPolicy("CorsPolicy",
                  builder =&gt; builder
                      .AllowAnyMethod()
                      .AllowAnyHeader()
                      .AllowCredentials()
                      .SetIsOriginAllowed((host) =&gt; true) //allow all connections (including Signalr)
                  );
          });
  </code></pre>
  
  <p>the important part being <code>.SetIsOriginAllowed((host) =&gt; true)</code>  This allows all connections for both website and signalr cors access.</p>
  
  <p>I had not added </p>
  
  <pre><code>services.AddAuthorization(options =&gt;
      {
          options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =&gt;
          {
              policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
              policy.RequireClaim(ClaimTypes.NameIdentifier);
          });
      });
  </code></pre>
  
  <p>I had only used <code>services.AddAuthentication(a =&gt;</code></p>
  
  <p>I took the following directly from the samples in github</p>
  
  <pre><code>            options.Events = new JwtBearerEvents
              {
                  OnMessageReceived = context =&gt;
                  {
                      var accessToken = context.Request.Query["access_token"];
  
                      if (!string.IsNullOrEmpty(accessToken) &amp;&amp;
                          (context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream"))
                      {
                          context.Token = context.Request.Query["access_token"];
                      }
                      return Task.CompletedTask;
                  }
              };   
  </code></pre>
  
  <p>Not sure if this was needed in the attribute, but the same used it on its hubs</p>
  
  <pre><code>    [Authorize(JwtBearerDefaults.AuthenticationScheme)]
  </code></pre>
  
  <p>with that I could not get multiple website and console apps to connect and communicate via signalr.</p>