I configured Twitch authentication for my website using this tutorial: https://blog.elmah.io/cookie-authentication-with-social-providers-in-asp-net-core/
In the Twitch dev console I added the https://localhost:44348/signin-twitch url to the callback urls. I've implemented oauth for other providers before, but having troubles with Twitch.
When I try to login, I get the Twitch authorization screen, but after clicking 'Authorize' it redirects me to /signin-twitch + params which returns a Correlation Failed exception.
Exception: An error was encountered while handling the remote login.
I have a feeling it might have to do with the routing. It's setup like this because I have a frontend application with it's own routing (hence the Fallback)
Here is all relevant code.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = "/signin";
options.LogoutPath = "/signout";
})
.AddTwitch(TwitchAuthenticationDefaults.AuthenticationScheme, options =>
{
options.ClientId = "xxx";
options.ClientSecret = "xxx";
options.Scope.Add("user:read:email");
options.SaveTokens = true;
options.AccessDeniedPath = "/";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapFallbackToController("Index", "Home");
});
}
public class AuthenticationController : Controller
{
[HttpGet("~/signin")]
public IActionResult SignIn(string returnUrl = "")
{
return Challenge(TwitchAuthenticationDefaults.AuthenticationScheme);
}
}
I think that the error occurs because you're trying to access the URL which is assigned as Callback Path.
Try some variant of this:
[HttpGet("~/signin")]
public IActionResult SignIn()
{
var authProperties = _signInManager
.ConfigureExternalAuthenticationProperties("Twitch",
Url.Action("LoggingIn", "Account", null, Request.Scheme));
return Challenge(authProperties, "Twitch");
}
Source: this answer and this one.
Other stuff to check:
Multiple clients with the same Callback Path
CookiePolicyOptions
HTTPS redirect
Related
I'm developing an application using ASP.Net Core MVC 3.1 and i am facing a problem where it fails to sign-in. localhost response 401 unauthorized
AccountController
[HttpPost]
public async Task<IActionResult> Login(PixClient client)
{
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Email, client.Email));
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(principal));
return RedirectToAction("Index", "Home");
}
Startup.cs
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.LoginPath = "/account/login";
options.Cookie.Name = "sessionid";
});
Index.cs
[Authorize]
public IActionResult Index()
{ ...
I checked the codes you've shown,there's no mistake in it.
Make sure you've added the Authentication middleware and it was in correct order:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
.......
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
......
}
And you could create a middleware to check if the ticked is generated and added to cookie successfully:
app.Use(async (context, next) =>
{
var cookies = context.Request.Cookies;
await next.Invoke();
});
I tried as below:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie( m =>
{
m.LoginPath = new Microsoft.AspNetCore.Http.PathString("/Home/Login");
m.Cookie.Name = "CookieAuth";
});
When redirect to /Home/Login,you could see the cookie namedCookieAuth:
I have added identity in asp.net core 3.1, How can i set identity login page as default and after successfully login it should redirect to particular page ?
In the Public void ConfigureServices(IServiceCollection services) method add the following codes at the bottom:
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(15);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
Note the LoginPath and AccessDeniedPath properties. Change the other properties to fit your requirements.
For the redirection it is actually coded in the login action which will redirect the user to a specific page. On successful login write the followings to redirect to the root page:
returnUrl = returnUrl ?? Url.Content("~/");
return LocalRedirect(returnUrl);
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(15);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
I am using Basic Authentication and I have created a Middleware for this. When I use the Authorize attribute and try to make an API call through Postman, i get 401 Unauthorize even as I am added the authorization details in Postman.
I am not sure if it is the way i am calling the controller action via postman or whether I am missing a header option in postman.
ConfigureServices
services
.AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme)
.AddBasicAuthentication(GetBasicAuthenticationOptions(users));
Configure
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
app.UseCors("SiteCorsPolicy");
app.UseAuthentication();
}
Basic Authentication Implementation
private Action<BasicAuthenticationOptions> GetBasicAuthenticationOptions(IList<UserConfiguration> users)
{
return options =>
{
options.Realm = "Public API";
options.Events = new BasicAuthenticationEvents
{
OnValidatePrincipal = context =>
{
var authenticatedUser = users.FirstOrDefault(u =>
u.Username == context.UserName && u.Password == context.Password);
if (authenticatedUser != null)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name,
context.UserName,
context.Options.ClaimsIssuer)
};
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims,
BasicAuthenticationDefaults.AuthenticationScheme));
context.Principal = principal;
return Task.CompletedTask;
}
return Task.FromResult(AuthenticateResult.Fail("Authentication failed."));
}
};
};
}
Controller Action with Authorize
[Authorize]
[HttpPost]
[Route("test")]
public IActionResult Test()
{
return Json("yes");
}
Postman request
The username and passwords are in the appsettings.json file
The issue was just because app.UseMvc(); was placed before app.UseAuthentication(); . I just had to place app.UseMvc(); after app.UseAuthentication(); and that fixed it.
When the server I'm authenticating with responds with the redirect back to my callback URL, my code doesn't seem to know how to handle the request - as if I'm missing a handler.
I thought the CallbackPath property would wire this up and pass the incoming request to my handler, is that not correct?
I just get a 404 from my app, the URL has the code=XXXX etc.
Here's my code
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
string authScheme = CookieAuthenticationDefaults.AuthenticationScheme;
services.AddAuthentication(o =>
{
o.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultAuthenticateScheme = "MyAuthScheme";
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddOAuth(authScheme, options =>
{
options.ClientId = "xxxxxxxxxxxxxxxxxxxxxxxx";
options.AuthorizationEndpoint = "https://example.com/adfs/oauth2/authorize?resource=https://example.net/";
options.TokenEndpoint = "https://example.com/adfs/oauth2/token";
options.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/signin-myauthserver");
options.ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxx";
});
services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
}
I'm running the RC1 of ASP.NET MVC 6 and would like to use a MongoDB Identity Provider.
I have implemented the provider by Grant Megrabyan which is doing a great job of registering new users and allowing them to log in but I get the error:
InvalidOperationException: No authentication handler is configured to handle the scheme: Microsoft.AspNet.Identity.External
Microsoft.AspNet.Http.Authentication.Internal.DefaultAuthenticationManager.d__13.MoveNext()
I had the external login previously working using EntityFramework so I'm assuming my configuration for third party auth is probably correct.
When the user clicks login with Facebook they are redirected to the following action :
// POST: /Account/ExternalLogin
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return new ChallengeResult(provider, properties);
}
There is no exception thrown at this point however when the Facebook returns from the ChallengeResponse it sends a GET to : http://localhost:51265/signin-facebook?code=[facebook user token].
At this point ASP.NET throws the exception:
The callback url made by Facebook doesn't seem to make sense. Surely it should return to my ExternalLoginCallback action?
It's about here that I'm out of ideas?!
If anyone can see where I've gone wrong then I'd be a very happy guy.
My startup.cs:
public class Startup
{
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ApplicationDbContext>();
// Add framework services.
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddMongoStores<ApplicationDbContext, ApplicationUser, IdentityRole>()
.AddDefaultTokenProviders();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
app.UseStaticFiles();
app.UseFacebookAuthentication(options =>
{
options.AppId = "removed";
options.AppSecret = "removed";
});
app.UseIdentity();
app.UseMvcWithDefaultRoute();
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
Call UseFacebookAuthentication after UseIdentity, but before UseMvc;
app.UseIdentity();
app.UseFacebookAuthentication(options =>
{
options.AppId = "removed";
options.AppSecret = "removed";
});
app.UseMvcWithDefaultRoute();
Edit:
I think the problem is the Order of defining configurations. Try to add Identity first then Facebook Authentication.
** Suggested Example **
app.UseIdentity();
app.UseMvcWithDefaultRoute();
app.UseFacebookAuthentication(options =>
{
options.AppId = "removed";
options.AppSecret = "removed";
});