I've been looking all over, and cannot figure out how to get the access token from a query string to be used with Signalr. Could somebody by chance help provide an example?
I've tried doing both this:
.AddValidation(options =>
{
options.AddEventHandler<OpenIddictValidationEvents.RetrieveToken>(
notification =>
{
notification.Context.Token = notification.Context.Request.Query["access_token"];
return Task.CompletedTask;
});
});
and this:
services.AddAuthentication()
.AddOAuthValidation(options =>
{
options.Events.OnRetrieveToken = context =>
{
context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
};
});
in my Startup.cs file (as found in another issue here)
Is there something I am missing? I'm using .net core 2.1. Thank you so much in advance for any help! I've been stuck on this for quite a while.
My code on the client side looks like this:
this.connection = new this.$signalR.HubConnectionBuilder()
.withUrl("/authTest?access_token=" + token)
.configureLogging(this.$signalR.LogLevel.Error)
.build();
which gives this error:
signalr.min.js:16 POST https://localhost:44318/authTest/negotiate?access_token=XXXXXX 401 ()
Okay I feel a little stupid, and finally figured this out (ironically pretty quickly after posting the issue). The key is that if you add to the OAuthValidation options - in services.AddOauthValidation(options => ...), then you must completely comment out the .AddValidation(); after .AddServer in services.AddOpenIddict();
For example here's a sample of working code, that does not use JWT tokens:
services.AddOpenIddict()
.AddCore(options =>
{
// Configure OpenIddict to use the default entities.
//options.UseDefaultModels();
// Register the Entity Framework stores.
//options.AddEntityFrameworkCoreStores<DefaultDbContext>();
options.UseEntityFrameworkCore()
.UseDbContext<DefaultDbContext>();
})
.AddServer(options =>
{
// Register the ASP.NET Core MVC binder used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
//options.AddMvcBinders();
options.UseMvc();
// Enable the authorization, logout, token and userinfo endpoints.
options.EnableAuthorizationEndpoint("/api/connect/authorize")
.EnableLogoutEndpoint("/api/connect/logout")
.EnableTokenEndpoint("/api/connect/token")
.EnableUserinfoEndpoint("/api/userinfo");
// Allow client applications to use the code flow.
// Allow client applications to use the grant_type=password flow.
options.AllowAuthorizationCodeFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow()
.AllowCustomFlow("urn:ietf:params:oauth:grant-type:facebook_access_token");
// Mark the "profile" scope as a supported scope in the discovery document.
options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
options.SetAccessTokenLifetime(TimeSpan.FromDays(1));
// When request caching is enabled, authorization and logout requests
// are stored in the distributed cache by OpenIddict and the user agent
// is redirected to the same page with a single parameter (request_id).
// This allows flowing large OpenID Connect requests even when using
// an external authentication provider like Google, Facebook or Twitter.
options.EnableRequestCaching();
// During development, you can disable the HTTPS requirement.
options.DisableHttpsRequirement();
});
//.AddValidation();
services.AddAuthentication()
.AddOAuthValidation(options =>
{
options.Events.OnRetrieveToken = context =>
{
context.Token = context.Request.Query["access_token"];
return Task.CompletedTask;
};
});
Now the access_token in the query string will work to authenticate your users with Signalr - by placing the [Authorize(AuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)] above the Hub class, just as you would in the Controller.
Most helpful comment
Okay I feel a little stupid, and finally figured this out (ironically pretty quickly after posting the issue). The key is that if you add to the OAuthValidation options - in services.AddOauthValidation(options => ...), then you must completely comment out the .AddValidation(); after .AddServer in services.AddOpenIddict();
For example here's a sample of working code, that does not use JWT tokens:
Now the access_token in the query string will work to authenticate your users with Signalr - by placing the [Authorize(AuthenticationSchemes = OAuthValidationDefaults.AuthenticationScheme)] above the Hub class, just as you would in the Controller.