No sign-out authentication handler is registered for the scheme 'Identity.TwoFactorUserId' - asp.net-core-2.0

ASP.NET Core 2.2 web app using code migrated from full fat MVC app.
My AccountController contains this simple code for its Logout route.
await this.SignInManager.SignOutAsync();
return this.RedirectToAction(nameof(Landing.HomeController.Index), "Home");
But this gives.
No sign-out authentication handler is registered for the scheme 'Identity.TwoFactorUserId'.
Pretty confusing given that I've never mentioned 2FA in my code, and Google login is working.
serviceCollection
.AddIdentityCore<MyUser>(identityOptions =>
{
identityOptions.SignIn.RequireConfirmedEmail = false;
})
.AddUserStore<MyUserStore>()
.AddSignInManager<SignInManager<MyUser>>();
serviceCollection.AddAuthentication(IdentityConstants.ApplicationScheme)
.AddCookie(IdentityConstants.ApplicationScheme, options =>
{
options.SlidingExpiration = true;
})
.AddGoogle(googleOptions =>
{
this.Configuration.Bind("OAuth2:Providers:Google", googleOptions);
googleOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
})
.AddExternalCookie();

As a complement to #Luke's answer:
The reason why SignInManager::SignOutAsync() throws is this method will also sign out the TwoFactorUserIdScheme behind the scenes:
public virtual async Task SignOutAsync()
{
await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
await Context.SignOutAsync(IdentityConstants.ExternalScheme);
await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme);
}
(See source code)
Typically, these tree authentication schemes are registered automatically by AddIdentity<TUser, TRole>():
public static IdentityBuilder AddIdentity<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
...
.AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
{
o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
});
... // other services
}
(See source code )
However, you added the Identity services by AddIdentityCore<>() instead of the AddIdentity<>().
Because the AddIdentityCore<>() doesn't register a TwoFactorUserIdScheme scheme (see source code) automatically, there's no associated CookieAuthenticationHandler for TwoFactorUserIdScheme. As a result, it throws.
How to solve
In order to work with SignInManager.SignOutAsync(), according to above description, we need ensure a <scheme>-<handler> map has been registed for TwoFactorUserIdScheme .
So I change your code as below, now it works fine for me:
serviceCollection.AddAuthentication(IdentityConstants.ApplicationScheme)
.AddCookie(IdentityConstants.ApplicationScheme, options =>
{
options.SlidingExpiration = true;
})
.AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
{
o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
})
.AddGoogle(googleOptions =>
{
this.Configuration.Bind("OAuth2:Providers:Google", googleOptions);
googleOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
})
.AddExternalCookie();

Also you can create your own SignInManager<MyUser> and override sign out as you need
public class CustomSignInManager : SignInManager<MyUser>
{
public override async Task SignOutAsync()
{
await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
await Context.SignOutAsync(GoogleDefaults.AuthenticationScheme);
}
}
Then change AddSignInManager<SignInManager<MyUser>>() to AddSignInManager<CustomSignInManager>() in your Startup class
serviceCollection
.AddIdentityCore<MyUser>(identityOptions =>
{
identityOptions.SignIn.RequireConfirmedEmail = false;
})
.AddUserStore<MyUserStore>()
.AddSignInManager<CustomSignInManager>();

Do not use the SignOutAsync method on a SignInManager<T> you've injected into the controller. Instead, use the method on the HttpContext which takes a scheme argument. I don't know why.

Below code works for me , use the same AuthenticationScheme that you use while "AddAuthentication" in startup.cs
[HttpGet("signout")]
[AllowAnonymous]
public async Task signout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var prop = new AuthenticationProperties
{
RedirectUri = "/logout-complete"
};
// after signout this will redirect to your provided target
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, prop);
}
[HttpGet("logout-complete")]
[AllowAnonymous]
public string logoutComplete()
{
return "logout-complete";
}

I agree with itminus reply, We would get an error because in .net core 3.0 if we use AddIdentityCore<>() instead of AddIdentity<>() we would get an error. But when upgrading to .net 7.0 if we again use AddIdentityCore<>() instead of AddIdentity<>() we would get the same error for Identity.TwoFactorRememberMeScheme as well that I am faced with after upgrading. For SignInManager we require Identity.TwoFactorRememberMeScheme as well otherwise we get an error.
The solution which I applied in mine .net 7.0 project is:
Instead of adding every scheme and handler by yourself, we can just use
services.AddAuthentication().AddIdentityCookies();
This will add all the schemes handlers for you and at the time of signout we need to should use below:
await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
await HttpContext.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme);

Related

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?
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
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.

identity server4, differents behaviors of login locally / azure

Environments : localhost / azure, .netcore 3.1 mvc identityserver4 + mvc api client.
When I run my application locally, the login/logout works fine, there is :
- an identityserver4 mvc .netcore 3.1
- a client mvc api .netcore 3.1
I can login / logout as much as I want, the login always redirects to the identityserver4 login and the login works.
When the same application with the identityserver4 hosted on Azure
The first login correctly redirects to the azure identityserver4, and login works fine.
Then after the logout (cockies seem to be removed), when I try login again, the redirection to the login page doesn't work and there is an "implicit" login and a direct redirection to the homepage of the website.
The client mvc api is configured like this :
{
"ClientId": "IdentityServer.WebApi",
"ClientSecret": "IdentityServer.WebApi",
"AllowedGrantTypes": "GrantTypes.CodeAndClientCredentials",
"RedirectUris": [
"https://localhost:44372/signin-oidc",
"https://localhost:5001/signin-oidc",
"https://192.168.1.7:44372/signin-oidc",
"https://mogui:44372/signin-oidc"
],
"PostLogoutRedirectUris": [
"https://localhost:44372/signout-callback-oidc",
"https://localhost:5001/signout-callback-oidc",
"https://192.168.1.7:44372/signout-callback-oidc",
"https://mogui:44372/signout-callback-oidc"
],
"AllowedScopes": [
"openid",
"profile"
],
"RequireConsent": true,
"RequirePkce": true,
"AllowOfflineAccess": true
},
The identityserver4 locally / on azure have this kind of code on its Startup class :
public void ConfigureServices(IServiceCollection services)
{
try
{
telemetryClient.TrackTrace("============== Startup ConfigureServices ============== ");
// uncomment, if you wan to add an MVC-based UI
services.AddControllersWithViews();
//services.AddMvc();
string connectionString = Configuration.GetConnectionString("IdentityDbContextConnection");
//const string connectionString = #"Data Source=(LocalDb)\MSSQLLocalDB;database=IdentityServer4.Quickstart.EntityFramework-3.0.102;trusted_connection=yes;";
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<IdentityServer.Models.IdentityDbContext>(options =>
options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly))
);
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<IdentityServer.Models.IdentityDbContext>()
.AddDefaultTokenProviders();
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
})
.SetCompatibilityVersion(CompatibilityVersion.Latest);
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
.AddSigningCredential(X509.GetCertificate("B22BBE7C991CEF13F470481A4042D1E091967FCC")) // signing.crt thumbprint
.AddValidationKey(X509.GetCertificate("321ABA505F6FCDDD00AA5EC2BD307F0C9002F9A8")) // validation.crt thumbprint
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
options.EnableTokenCleanup = true;
})
.AddAspNetIdentity<ApplicationUser>();
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "174637674775-7bgu471gtme25sr5iagq5agq6riottek.apps.googleusercontent.com";
options.ClientSecret = "V_UsR825ZWxCB9i2xrN-u1Kj";
});
services.AddTransient<IEmailSender, IdentityEmailSender>();
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Strict;
});
services.AddScoped<IProfileService, ProfileService>();
telemetryClient.TrackTrace("============== Startup ConfigureServices finish OK ============== ");
}
catch (Exception e)
{
telemetryClient.TrackTrace("Exception general in ConfigureServices");
telemetryClient.TrackException(e);
throw;
}
}
and this :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
try
{
telemetryClient.TrackTrace("============== Startup Configure ============== ");
InitializeDatabase(app);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseCors("AllowAll");
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
app.UseMvcWithDefaultRoute();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
telemetryClient.TrackTrace("============== Startup Configure finish OK============== ");
}
catch (Exception e)
{
telemetryClient.TrackTrace("Exception general in Configure");
telemetryClient.TrackException(e);
throw;
}
}
So the problem is with
the identityserver4 localhost the login / logout works find
the idnetityserver4 hosted on azure the login is skipped and go diectly to the homepage (the user is authenticated with previous login).
Sorry to be a little long,
I haven't seen this exact problem on stackoverflow or somewhere else.
Thanx in advance !
There are several things that can go wrong with moving your app to production.
I suspect that if you are redirected back to your Homepage, that the auth cookies are not being removed by your SignOutAsync("Cookies) call.
Check these:
PostLogoutRedirectUris contain your azure domain + "signout-callback-oidc"
Check on what path is your Auth cookies created. If different from "/" - add the default path. I guess in your case it would be somewhat among the lines of:
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true,
Path = "/"
};
You're right Riste,
According to differents posts I've seen, we can do such a thing :
- first of all, we have to put FrontChannelLogoutUri parameter
(it should be an mvc client controller/action called by identityserver4, in our case
should be something like https://localhost:999/Account/FrontChannelLogout) for the client mvc app, generally it is put in Config.cs and add this parameter for the client Mvc (with RedirectUris, PostLogoutRedirectUris, ...)
- on the client mvc, in an account controller (for instance) where is managed the login ,
we can add / modifiy the logout management :
[Authorize]
public async Task<IActionResult> Logout()
{
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync($"https://{Startup.Configuration["Auth0:Domain"]}");
return Redirect(disco.EndSessionEndpoint);
}
public async Task<IActionResult> FrontChannelLogout(string sid)
{
if (User.Identity.IsAuthenticated)
{
var currentSid = User.FindFirst("sid")?.Value ?? "";
if (string.Equals(currentSid, sid, StringComparison.Ordinal))
{
await HttpContext.SignOutAsync("oidc");
await HttpContext.SignOutAsync("Identity.Application");
await _signInManager.Context.SignOutAsync("_af");
await _signInManager.Context.SignOutAsync("idsrv.session");
await _signInManager.Context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
}
}
return NoContent();
}
On the identityserver4 side :
In the QuickStart Account Controller, we have to update the BuildLoggedOutViewModelAsync method :
private async Task<LoggedOutViewModel> BuildLoggedOutViewModelAsync(string logoutId)
{
// get context information (client name, post logout redirect URI and iframe for federated signout)
var logout = await _interaction.GetLogoutContextAsync(logoutId);
var client = await _clientStore.FindEnabledClientByIdAsync(logout.ClientIds.First());
if (!string.IsNullOrEmpty(client.FrontChannelLogoutUri))
{
//var pos = GetNthIndex(client.FrontChannelLogoutUri, '/', 3);
//logout.PostLogoutRedirectUri = client.FrontChannelLogoutUri.Substring(0, Math.Min(client.FrontChannelLogoutUri.Length, pos));
// Here TODO =====> get the real PostLogoutRedirectUri, it should be a controller/action url on the client mvc side and put it in **logout.PostLogoutRedirectUri**
}
var vm = new LoggedOutViewModel
{
AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName,
SignOutIframeUrl = logout?.SignOutIFrameUrl,
LogoutId = logoutId
};
if (User?.Identity.IsAuthenticated == true)
{
var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
if (idp != null && idp != IdentityServer4.IdentityServerConstants.LocalIdentityProvider)
{
var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp);
if (providerSupportsSignout)
{
if (vm.LogoutId == null)
{
// if there's no current logout context, we need to create one
// this captures necessary info from the current logged in user
// before we signout and redirect away to the external IdP for signout
vm.LogoutId = await _interaction.CreateLogoutContextAsync();
}
vm.ExternalAuthenticationScheme = idp;
}
}
}
return vm;
}
====> Apparently _interaction.GetLogoutContextAsync(logoutId) never return a PostLogoutRedirectUri even though it has been set up for the mvc client (in the Config.cs).
====> by filling this parameter logout.PostLogoutRedirectUri on identityServer4 side it'll redirect the logout to the client app.
Here is what I can say, I don't know if the logout redirect to the client app is a "standard" behavior, don't know if it was planned in identityserver4.
Some links :
https://andersonnjen.com/2019/03/22/identityserver4-global-logout/
How to redirect user to client app after logging out from identity server?
Thanx !

Identity Server 4 - User Claims empty on linux

Problem:
On Linux server User Claims are not passing from Auth to API. On Windows machine everything works fine (under VS2017 and using CMD)
I have Controller with special authorization attribute:
[Authorize(Policy = "identity")]
[Route("routes")]
public class RoutesController : Controller
{
[HttpGet]
public IActionResult Get(string postId, string routeType)
{
//
}
In Startup.cs I have provided proper entries:
services.AddMvc(options => {
options.Filters.Add(new AuthorizeFilter("identity"));
});
services.AddAuthorization(options => {
options.AddPolicy("identity", policy =>
{
policy.Requirements.Add(new IdentityUserRequirement());
});
});
services.AddSingleton<IAuthorizationHandler, IdentityUserHandler>();
And created proper class in /Filters directory:
public class IdentityUserHandler : AuthorizationHandler<IdentityUserRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IdentityUserRequirement requirement)
{
UserModel user = _userRepository.FindById(context.User.Claims.SingleOrDefault(x => x.Type == "userid")?.Value);
user.IMEI = context.User.Claims.SingleOrDefault(x => x.Type == "imei")?.Value;
_userRepository.UpdateUser(user);
context.Succeed(requirement);
return Task.FromResult(0);
}
}
Using Postman I'm calling Auth service to gain access_token, then using that token I'm calling my RoutesController Get method.
On Windows (launching services under VS2015 or launching services via CMD) method returns normal JSON with Routes.
When I've deployed solution on Linux following error appeared:
NullReferenceException: Object reference not set to an instance of an object.
And is reffering to my IdentityUserHandler class method HandleRequirementAsync to line:
user.IMEI = context.User.Claims.SingleOrDefault(x => x.Type == "imei")?.Value;
As far i manager to debug Linux enviroment looks like there is a problem with:
AuthorizationHandlerContext context
parameter in method HandleRequirementAsync
Collection contex.User.Claims has no elements. On Windows has, on Linux no.
Anybody knows why?
I've made some tests and it looks like this is working only on my developers machine, on:
Centos
Win Server 2k8
Win Sever 2k16
Problem exist

Swagger authentication in Azure App Service

In my Azure Mobile .NET backend I want to use Azure Mobile .NET Server Swagger . I'm looking for fast way to hide swagger UI from public access ? Is there any way to provide access only for selected users ?
First a disclaimer: Even if you protect your Swagger UI from public consumption, you are not protecting your APIs from public consumption. You have to assume that everyone knows all of your routes and have the appropriate security in place to protect any requests that may come in.
That being said, there's still not a simple way to do this. Swashbuckle (the piece that adds Swagger to Web API) adds a custom HttpMessageHandler to the /swagger/ui route (as seen here). If you look at the Web API pipeline, you can see that if you specify a custom handler, you can bypass all of the Controller selection, Auth filters, etc. This is what happens here.
Some solutions:
Use an app setting to conditionally call ConfigureSwagger(config) in debug modes only. This would prevent all /swagger routes from making it into production. Or you could use a staging slot and only add it there.
You can wrap the SwaggerUiHandler with something like this Basic Auth MessageHandler. This would prompt the user for basic creds if they went to the /swagger/ui route. See below for my modified version of this code.
Maybe with a little more thought we can come up with a better solution -- I see a couple of issues (here and here) in the Swashbuckle repo that indicate you're not the first one to hit this.
Modified BasicAuthHandler (from here):
Warning: minimally tested (and be sure to change how you verify user/pass)
public class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic";
public BasicAuthMessageHandler(HttpMessageHandler innerHandler)
{
this.InnerHandler = innerHandler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AuthenticationHeaderValue authValue = request.Headers.Authorization;
HttpResponseMessage unauthorizedResponse = request.CreateUnauthorizedResponse();
if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter))
{
Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
if (parsedCredentials != null)
{
// TODO: Check that the user/pass are valid
if (parsedCredentials.Username == "user" &&
parsedCredentials.Password == "pass")
{
// If match, pass along to the inner handler
return base.SendAsync(request, cancellationToken);
}
}
}
else
{
// Prompt for creds
unauthorizedResponse.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
}
return Task.FromResult(unauthorizedResponse);
}
private Credentials ParseAuthorizationHeader(string authHeader)
{
string[] credentials = Encoding.ASCII.GetString(Convert
.FromBase64String(authHeader))
.Split(
new[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0])
|| string.IsNullOrEmpty(credentials[1])) return null;
return new Credentials()
{
Username = credentials[0],
Password = credentials[1],
};
}
}
Registering with Swagger route
// Do this after calling ConfigureSwagger
ConfigureSwagger(config);
// Remove the swagger_ui route and re-add it with the wrapped handler.
var route = config.Routes["swagger_ui"];
config.Routes.Remove("swagger_ui");
config.Routes.MapHttpRoute("swagger_ui", route.RouteTemplate, route.Defaults, route.Constraints, new BasicAuthMessageHandler(route.Handler));

owin oauth webapi with a dynamic TokenEndpointPath (request for example)

I refer to post of David Snipp in https://stackoverflow.com/a/29706891/4609861 to kindly ask a little example of his explanation; I am having troubles calling delegate OnMatchEndpoint and the MatchesTokenEndpoint. thx
You can specify the delegates on Options itself in your Startup.cs code. Something along these lines:
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()
{
provider = new OAuthAuthorizationServerProvider()
{
OnMatchEndpoint = (context =>
{ // do your stuff
context.MatchesAuthorizationEndpoint();
return Task.FromResult<object>(0);
});
}
}

Resources