I created a sample project within VS 2017 using ASP.NET Core Templates 1.1 (Web Application) changing the authentication to be Individual User Accounts.
From there I followed the instructions at
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/
and
https://auth0.com/docs/quickstart/webapp/aspnet-core/01-login
The Startup.cs is essentially
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(
options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
services.AddMvc(options=>
{
options.SslPort = 44321;
options.Filters.Add(new RequireHttpsAttribute());
});
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.AddOptions();
services.Configure<Auth0Settings>(Configuration.GetSection("Auth0"));
}
// 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, IOptions<Auth0Settings> auth0Settings)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
// Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
var options = new OpenIdConnectOptions("Auth0")
{
Authority = $"https://{auth0Settings.Value.Domain}",
ClientId = auth0Settings.Value.ClientId,
ClientSecret = auth0Settings.Value.ClientSecret,
AutomaticAuthenticate = false,
AutomaticChallenge = false,
SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,
ResponseType = "code",
CallbackPath = new PathString("/signin-auth0"),
// Configure the Claims Issuer to be Auth0
ClaimsIssuer = "Auth0",
};
options.Scope.Clear();
options.Scope.Add("openid");
app.UseOpenIdConnectAuthentication(options);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
I register a user, navigate to manage your account and click, Manage link next to External Logins.
I click Auth0 button and successfully login. I get redirected to /Manage/LinkLoginCallback where the following method returns null.
private Task<ApplicationUser> GetCurrentUserAsync()
{
return _userManager.GetUserAsync(HttpContext.User);
}
Causing the following to appear
Error. An error occurred while processing your request. Development
Mode Swapping to Development environment will display more detailed
information about the error that occurred.
Development environment should not be enabled in deployed
applications, as it can result in sensitive information from
exceptions being displayed to end users. For local debugging,
development environment can be enabled by setting the
ASPNETCORE_ENVIRONMENT environment variable to Development, and
restarting the application.
I'm not sure what i'm doing wrong with respect to configuring Auth0 and Identity. In addition, if you know how to address the error above when the launchSettings.json does have ASPNETCORE_ENVIRONMENT as Development, that would also be much appreciated.
Related
Are there an explicit "Access-Control-Allow-Credentials" attribute to explicitly allow credentials to be sent with a request to a specific client site?
I have tried the following
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://my-account-name.github.io",
"http://my-account-name.github.io/My-repository",
"https://my-account-name.github.io",
"https://my-account-name.github.io/My-repository");
});
});
...
app.UseCors(MyAllowSpecificOrigins);
Not working solution source
And I get the "CORS" policy restriction in Chrome console nevertheless for those request that include credential headers and / or authorize cookies. Other requests (that don't include credentials) are passing fine with cors fetch() from JS.
The complete solution to the CORS Cookie Authorization is the SameSite = None; cookie policy (which you have to tell the browser explicitly from your server)
// Controller.cs
[EnableCors("_allowSpecific")] // !!!
public class YourController : Controller
// ...
// Startup.cs (.Net 5) / Program.cs (.Net 6-7 +)
string MyAllowSpecificOrigins = "_allowSpecific";
public void ConfigureServices(IServiceCollection services)
{
services.AddSession(options =>
{
options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None; // !!!
});
services.AddCors(options => {
options.AddPolicy(name: MyAllowSpecificOrigins,
policy => { policy.WithOrigins( "http://your-domain.your-site.com", "https://your-domain.your-site.io", "http://your-domain.your-site.io"
#if DEBUG // Use this for debugging CORS in NPM on another localhost port
, "http://localhost:8081", "https://localhost:8081", "http://127.0.0.1:8081", "http://192.168.1.64:8081"
#endif
).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
});
});
services.Configure<CookiePolicyOptions>(options => {
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None; // !!!
});
// ADD your services, DbContexts, Identity, Configure<IdentityOptions>, AddDefaultIdentity<IdentityUser>, AddRoles<IdentityRole>, AddEntityFrameworkStores<ApplicationDbContext>, ConfigureApplicationCookie, AddDatabaseDeveloperPageExceptionFilter, AddSingleton<IHttpContextAccessor>, AddRazorPages, AddControllersWithViews, AddLogging,
services.ConfigureApplicationCookie(options => {
// Cookie settings
options.Cookie.SameSite = SameSiteMode.None; // !!!
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(10000);
options.SlidingExpiration = true;
});
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IWebHostEnvironment env, Microsoft.Extensions.Hosting.IHostApplicationLifetime appLifetime)
{
// ...
app.UseCookiePolicy(new CookiePolicyOptions {
MinimumSameSitePolicy = SameSiteMode.None // !!!
});
// app.UseRouting(); ...
app.UseCors(MyAllowSpecificOrigins); // ? 1) not sure whether you need to use both, but it works
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(MyAllowSpecificOrigins); // ? 2) not sure if you need to use both, but it works
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
.RequireCors(MyAllowSpecificOrigins); // !!!
endpoints.MapRazorPages().RequireCors(MyAllowSpecificOrigins); // !!!
endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins); // !!!
});
}
//...
Not only this setup will allow you to use CORS autherization (using cookie headers), this will also allow Chrome to block any request from other than "_allowSpecific" origins.
I had to spend almost a year to figure this out.
We have a .NET 5 (Blazor Server) app running in Azure Kubernetes that uses OpenID Connect to authenticate with a 3rd party. The app is running behind Ingress. Ingress uses https. The app is only http. After we authenticate with OIDC and get redirected back to /signin-oidc, we get a .NET error that we haven't been able to solve.
warn: Microsoft.AspNetCore.Http.ResponseCookies[1]
The cookie '.AspNetCore.OpenIdConnect.Nonce.CfDJ8EYehvsxFBVNtGDsitGDhE8K9FHQZVQwqqr1YO-zVntEtRgpfb_0cHpxfZp77AdGnS35iGRKYV54DTgx2O6ZO_3gq98pbP_XcbHnJmBDtZg2g5hhPakTrRirxDb-Qab0diaLMFKdmDrNTqGkVmqiGWpQkSxcnmxzVGGE0Cg_l930hk6TYgU0qmkzSO9WS16UBOYiub32GF4I9_qPwIiYlCq5dMTtUJaMxGlo8AdAqknxTzYz4UsrrPBi_RiWUKaF6heQitbOD4V-auHmdXQm4LE' has set 'SameSite=None' and must also set 'Secure'.
warn: Microsoft.AspNetCore.Http.ResponseCookies[1]
The cookie '.AspNetCore.Correlation.MMrYZ2WKyYiV4hMC6bhQbGZozpubcF2tYsKq748YH44' has set 'SameSite=None' and must also set 'Secure'.
warn: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[15]
'.AspNetCore.Correlation.MMrYZ2WKyYiV4hMC6bhQbGZozpubcF2tYsKq748YH44' cookie not found.
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.Exception: An error was encountered while handling the remote login.
---> System.Exception: Correlation failed.
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
public class Startup
{
private static readonly object refreshLock = new object();
private IConfiguration Configuration;
private readonly IWebHostEnvironment Env;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Console.WriteLine($"LogQAApp Version: {Assembly.GetExecutingAssembly().GetName().Version}");
// We apparently need to set a CultureInfo or some of the Razor pages dealing with DateTimes, like LogErrorCountByTime fails with JavaScript errors.
// I wanted to set it to CultureInvariant, but that wouldn't take. Didn't complain, but wouldn't actually set it.
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
Configuration = configuration;
Env = env;
}
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // Needed for 1252 code page encoding.
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("");
services.AddSignalR(e =>
{
e.MaximumReceiveMessageSize = 102400000;
});
services.AddBlazoredSessionStorage();
services.AddCors();
services.AddSyncfusionBlazor();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddHttpContextAccessor();
ServiceConfigurations.LoadFromConfiguration(Configuration);
#region Authentication
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(
options =>
{
options.Events = GetCookieAuthenticationEvents();
}
)
.AddOpenIdConnect("SlbOIDC", options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = Configuration["SlbOIDC:Authority"];
if (Env.IsDevelopment())
{
options.ClientId = Configuration["SlbOIDC:ClientID"];
options.ClientSecret = Configuration["SlbOIDC:ClientSecret"];
}
else
{
options.ClientId = Configuration.GetValue<string>("slbclientid");
options.ClientSecret = Configuration.GetValue<string>("slbclientsecret");
}
options.ResponseType = OpenIdConnectResponseType.Code;
options.UsePkce = true;
options.SaveTokens = true;
options.ClaimsIssuer = "SlbOIDC";
// Azure is communicating to us over http, but we need to tell SLB to respond back to us on https.
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProvider = context =>
{
Console.WriteLine($"Before: {context.ProtocolMessage.RedirectUri}");
context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http://", "https://");
Console.WriteLine($"After: {context.ProtocolMessage.RedirectUri}");
return Task.FromResult(0);
}
};
});
services.AddSession(options =>
{
options.Cookie.SameSite = SameSiteMode.None;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.IsEssential = true;
});
#endregion
services.AddScoped<BrowserService>();
services.AddSingleton<ConcurrentSessionStatesSingleton>();
services.AddSingleton<URLConfiguration>();
services.AddScoped<CircuitHandler>((sp) => new CircuitHandlerScoped(sp.GetRequiredService<ConcurrentSessionStatesSingleton>(), sp.GetRequiredService<BrowserService>(), sp.GetRequiredService<IJSRuntime>()));
services.AddScoped<SessionServiceScoped>();
services.AddScoped<LogEditorScoped>();
services.AddSingleton<ModalService>();
services.AddFlexor();
services.AddScoped<ResizeListener>();
services.AddScoped<ApplicationLogSingleton>();
services.AddScoped<LogChartsSingleton>();
services.AddScoped<CurveNameClassificationSingleton>();
services.AddScoped<HubClientSingleton>();
services.AddScoped((sp) => new LogAquisitionScopedService(
sp.GetRequiredService<URLConfiguration>(),
sp.GetRequiredService<HubClientSingleton>(),
sp.GetRequiredService<ApplicationLogSingleton>(),
sp.GetRequiredService<IConfiguration>(),
sp.GetRequiredService<SessionServiceScoped>(),
sp.GetRequiredService<AuthenticationStateProvider>(),
sp.GetRequiredService<IHttpContextAccessor>(),
sp.GetRequiredService<IJSRuntime>()
)
);
services.AddScoped<UnitSingleton>();
services.AddServerSideBlazor().AddCircuitOptions(options => { options.DetailedErrors = true; });
services.AddScoped<TimeZoneService>();
services.AddHostedService<ExcelBackgroundService>();
services.AddHostedService<LogEditorBackgroundService>();
}
// 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("/Error");
//app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseCookiePolicy();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();
if (!Env.IsDevelopment())
{
app.UseTrafficManager();
}
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
private CookieAuthenticationEvents GetCookieAuthenticationEvents()
{
return new CookieAuthenticationEvents()
{
OnValidatePrincipal = context =>
{
lock (refreshLock)
{
if (context.Properties.Items.ContainsKey(".Token.expires_at"))
{
DateTime expire = DateTime.Parse(context.Properties.Items[".Token.expires_at"]);
if (expire.AddMinutes(-20) < DateTime.Now)
{
try
{
CloudAuthentication cloudAuthentication = new CloudAuthentication();
TokenResponse tokenResponse = cloudAuthentication.GetRefreshToken(context.Properties.Items[".Token.refresh_token"]);
context.Properties.Items[".Token.access_token"] = tokenResponse.access_token;
context.Properties.Items[".Token.refresh_token"] = tokenResponse.refresh_token;
context.Properties.Items[".Token.expires_at"] = DateTime.Now.AddSeconds(tokenResponse.expires_in).ToString();
context.ShouldRenew = true;
}
catch (Exception ex)
{
context.RejectPrincipal();
}
}
}
return Task.FromResult(0);
}
}
};
}
}
It's a good question - there are a couple of interesting points here that I've expanded on since they are related to SameSite cookies.
REVERSE PROXY SETUP
By default the Microsoft stack requires you to run on HTTPS if using cookies that require an SSL connection. However, you are providing SSL via a Kubernetes ingress, which is a form of reverse proxy.
The Microsoft .Net Core Reverse Proxy Docs may provide a solution. The doc suggests that you can inform the runtime that there is an SSL context, even though you are listening on HTTP:
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next();
});
I would be surprised if Microsoft did not support your setup, since it is a pretty mainstream hosting option. If this does not work then you can try:
Further searching around Blazor and 'reverse proxy hosting'
Worst case you may have to use SSL inside the cluster for this particular component, as Johan indicates
WIDER INFO - API DRIVEN OAUTH
Many companies want to develop Single Page Apps, but use a website based back end in order to manage the OAuth security. Combining serving of web content with OAuth security adds complexity. It is often not understood that the OAuth SPA security works better if developed in an API driven manner.
The below resources show how the SPA code can be simplified and in this example the API will issue cookies however it is configured. This would enable it to listen over HTTP inside the cluster (if needed) but to also issue secure cookies:
API driven OpenID Connect code
Curity Blog Post
WIDER INFO: SAMESITE COOKIES
It is recommended to use SameSite=strict as the most secure option, rather than SameSite=none. There are sometimes usability problems with the strict option however, which can cause cookies to be dropped after redirects or navigation from email links.
This can result in companies downgrading their web security to a less secure SameSite option. These problems do not occur when an API driven solution is used, and you can then use the strongest SameSite=strict option.
I installed AWS Toolkit for Visual Studio 2019 & created new "AWS Serverless Application(.NET Core C#)" project.
Following this video tutorial I configured new Cognito User Pool & edited the default project's Startup.cs & added secure page with [Authorize] attribute (at the 12min mark you can find the exact steps of how Cognito was configured).
After publishing to AWS (or even when debugging locally) when I navigate to secure page I correctly get redirected and prompted to login, but after successful login it enters a loop in the background that keeps sending back to OIDC authorization link & back to my site... after a few of those it throws an error of "ERR_TOO_MANY_REDIRECTS".
Any idea what is missing from this tutorial in order to make it work properly? The only step I skipped was that he registered a domain name for his site, while I'm just using the default site URL I get after right-clicking project & choosing "Publish to AWS Lambda".
Here's edited code of my Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
string clientId = "<cognito_app_client_id>";
string clientSecret = "<cognito_app_client_secret>";
string logoutUrl = "https://<published_app_aws_url>/logout";
string baseUrl = "https://<published_app_aws_url>";
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.ResponseType = OpenIdConnectResponseType.Code;
options.MetadataAddress = $"https://cognito-idp.<aws_region>.amazonaws.com/<cognito_pool_id>/.well-known/openid-configuration";
options.ClientId = clientId;
options.ClientSecret = clientSecret;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProviderForSignOut = (context) =>
{
var logoutUri = logoutUrl;
logoutUri += $"client_id={clientId}&logout_uri={baseUrl}";
context.Response.Redirect(logoutUri);
context.HandleResponse();
return Task.CompletedTask;
}
};
});
services.AddRazorPages();
}
// 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("/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.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Thanks to comment by Philip Pittle I found the UseAuthentication must come before UseAuthorization.
I'm getting this
No web page was found for the web address: https://limbu.azurewebsites.net/
Everything worked fine in development but after publishing I get this error.
I can navigate to Views by typing in url but not the index page. I'm also not able to perform Register and login functions from controller in published website.
My Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Production")
{
services.Configure<IServiceProvider>(options => {
options.GetService<AppDbContext>().Database.Migrate();
}).AddDbContextPool<AppDbContext>(options => {
options.UseSqlServer(_config.GetConnectionString("AzureSqlConnection"));
//options.EnableSensitiveDataLogging(true);
});
}
else
{
services.AddDbContextPool<AppDbContext>(options => options.UseSqlServer(_config.GetConnectionString("Connection")));
}
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
}).AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
services.AddTransient<IMailService, SendGridMailService>();
services.AddHostedService<TimedHostedServices>();
services.AddScoped<IGetGlobalCovidData, GetGlobalCovidData>();
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}).AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
//ServicePointManager.ServerCertificateValidationCallback += //This code is security risk as it validates all certificates
// (sender, certificate, chain, errors) => //Not to be used for production and used this instance as I trust the
// { //The site I'm pulling data from
// return errors == SslPolicyErrors.None;
// };
//services.AddLogging(loggingBuilder => { //This code is security risk as it displays all sensitive data
// loggingBuilder.AddConsole() //Not recommended for production
// .AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Information);
// loggingBuilder.AddDebug();
//});
}
// 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("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapDefaultControllerRoute();
});
}
Please advise me on what I should provide for debugging.
my .cshtml build action is -content and donotcopy
.cs build action is -c# compiler and donotcopy
For the users who are getting the same issue, There could be different root causes for 404 error messages. Sub-status codes will help you understand the issue better.
You may check whether the site files are deployed correctly or not through Kudu Console. Also, suggest you Enable diagnostics logging for web apps in Azure App Service incase if you haven’t enabled earlier to check the complete error details and root cause.
I'm migrating an ASP.NET Core MVC application from version 1.0.2 to 2.0.
I have in this application an external authentication via Facebook.
When I'm launching the web application I'm facing to this error:
InvalidOperationException: The SignInScheme for a remote authentication handler cannot be set to itself. If it was not explicitly set, the AuthenticationOptions.DefaultSignInScheme or DefaultScheme is used.
I searched here but it did not help me for now.
In my Startup.cs, the method "ConfigureServices" looks like this:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// If you want to tweak Identity cookies, they're no longer part of IdentityOptions.
services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
services.AddAuthentication()
.AddFacebook(options =>
{
options.AppId = Configuration["AuthenticationFacebookSettings:AppId"];
options.AppSecret = Configuration["AuthenticationFacebookSettings:AppSecret"];
options.SignInScheme = "Facebook";
options.SaveTokens = true;
});
services.Configure<AuthenticationFacebookSettings>(Configuration.GetSection("AuthenticationFacebookSettings"));
services.AddMvc();
// Add application services.
.
.
// my services
.
.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
The method "Configure" looks like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
I am missing something here because everything looks alright...
I spend a lot of time on this issue and I am clueless...
Thanks for your help!
The link of #ps2goat put me on right way.
I changed my Facebook options like this (by taking the default value):
services.AddAuthentication()
.AddFacebook(options =>
{
options.AppId = Configuration["AuthenticationFacebookSettings:AppId"];
options.AppSecret = Configuration["AuthenticationFacebookSettings:AppSecret"];
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.SaveTokens = true;
});
In fact with .NET Core 2.0 migration, I had to change the SignInScheme. In my case I did set it to the default value with:
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
More precisely, for launching the application it was not enough.
I had to update my view for using "GetExternalAuthenticationSchemesAsync()" method instead of "GetExternalAuthenticationSchemes()" method of the signin manager.
After adapting a little bit my code, it finally works. Thanks #ps2goat.