none
ASP.net Core 1 - Authentication cookie not being set in Google Chrome (works in IE) RRS feed

  • Question

  • Hi,

    I'm using ASP.net Core 1, MVC 6.  I am using SignInManager and UserManager, to authenticate a user in a web api application (MVC6 / C#) from another MVC application (the web api Logon method is actually called from a Jquery Ajax request). 

    In IE, I call the Login method and when successful, it gives me a Set-Cookie response with an ASP.net auth cookie.  I can then see subsequent requests have the ASP.net auth cookie attached. 

    In chrome, the Set-Cookie directive is returned in the response, but subsequent requests do not have the cookie attached.

    Why is this happening?  The only difference I can see is that in Chrome, there is a pre-flight OPTIONS request being sent, but I have handled that in the startup.cs file in the web api and am essentially ignoring it. 

    IE

    My request to Login web api looks like this:

    Accept */*
    Accept-Encoding gzip, deflate
    Accept-Language en-IE
    Cache-Control no-cache
    Connection Keep-Alive
    Content-Length 246
    Content-Type application/x-www-form-urlencoded; charset=UTF-8
    Cookie BeaeN4tYO5M=CfDJ8KMNkK4F2ylMlo1LFxNzxWLNDECVWfhxBYRQrw_MkNQBrVIwfO6FoMIMqg1PP-nZa8Dhp3IV1ZS1uXKpknUDYegiMlEvFaNG-wqUXErvQ5wkMMc_HBI88j-7bCbD2Q7P_B6fEQOQSTKHoL5sTcH0MoM
    DNT 1
    Host localhost:44338
    Referer https://localhost:44356/
    Request POST /api/account/Login HTTP/1.1
    User-Agent Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
    X-ACL-Key 4A6F0007-95E7-4423-B786-6FBF981799FE

    Response like this:

    Key Value
    Response HTTP/1.1 200 OK
    Cache-Control no-cache
    Pragma no-cache
    Content-Type application/json; charset=utf-8
    Expires -1
    Server Kestrel
    Set-Cookie oAuthInterop=CfDJ8Asqo6qO2cNHlXpsdNLsuoQWhLxXcnaNkAMTB-VvpkMRIz2AiM_7feoIM29gza_zZz97qaE6TKdqK8y1jDPjDDyiiMdOMiuCmCoV5X4IQ9xtHvpGgmFoxOSiYFVeVOBbHsLx4BccL647F9sJ07M55zvjMx_7wrt32omhONH64vmc12P3nepwZjNSIFYfom1U0Z4r4EX_0tZjKRH7FrdvO0PI2iY5SMaKhCcBw1QXpQHSUxL6Hm-Wr8Q46gFAYoa6YffJV0Rx80FvJHmr1LMAA6PAF0dU_DzNdRVHdXm14t_nbfl-6xb6o7WQN259moUhkT1ZQ9CZsYwWvn7VBmpjfIXNJvIu0FDnRaHnNMrj3uN77_cAMdO3OcyCuy-CAKJ9c-0PxKToStb9juGSNa9ClpVQPADzpUxFqxZU029AXBPavXQK2Ezvy7YT4FwCkL8TEf5AnB5hfOZ5YCBlqD30n2heMdHDbXRHpxeaQB4aoY_6uSpJ3cPazBDsbvGi4fV2-0g5NvoTGgJUXa5p4UntRmuiJ2tZHbMmEjXzf-GV6QtTFIhseKsS3n6TMX68yqQOhYOzxvHdJXPjYxvjmm6-vJw5w2FDgiEXoQJQ7qaSmGzRwOA_cE4VBV_RhzrZELmp3A; path=/; secure; httponly
    X-SourceFiles =?UTF-8?B?QzpcVXNlcnNcUm9iZXJ0XERlc2t0b3BcSEJFIE1hbmFnZXJcTUFJTlxCbHVlem9uZSBXZWJBcGlcc3JjXEJ6LkFwcGxpY2F0aW9uXEJ6LkFwcGxpY2F0aW9uLkFwaVx3d3dyb290XGFwaVxhY2NvdW50XExvZ2lu?=
    X-Powered-By ASP.NET
    Access-Control-Allow-Methods GET,PUT,POST,DELETE
    Access-Control-Allow-Headers Content-Type,x-xsrf-token,X-ACL-Key
    Date Fri, 06 May 2016 14:23:22 GMT
    Content-Length 16

    Subsequent test web api call (IsLoggedIn):

    Key Value
    Request GET /api/account/IsLoggedIn HTTP/1.1
    X-ACL-Key 4A6F0007-95E7-4423-B786-6FBF981799FE
    Accept */*
    Referer https://localhost:44356/
    Accept-Language en-IE
    Accept-Encoding gzip, deflate
    User-Agent Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
    Host localhost:44338
    DNT 1
    Connection Keep-Alive
    Cache-Control no-cache
    Cookie BeaeN4tYO5M=CfDJ8KMNkK4F2ylMlo1LFxNzxWLNDECVWfhxBYRQrw_MkNQBrVIwfO6FoMIMqg1PP-nZa8Dhp3IV1ZS1uXKpknUDYegiMlEvFaNG-wqUXErvQ5wkMMc_HBI88j-7bCbD2Q7P_B6fEQOQSTKHoL5sTcH0MoM; oAuthInterop=CfDJ8Asqo6qO2cNHlXpsdNLsuoQWhLxXcnaNkAMTB-VvpkMRIz2AiM_7feoIM29gza_zZz97qaE6TKdqK8y1jDPjDDyiiMdOMiuCmCoV5X4IQ9xtHvpGgmFoxOSiYFVeVOBbHsLx4BccL647F9sJ07M55zvjMx_7wrt32omhONH64vmc12P3nepwZjNSIFYfom1U0Z4r4EX_0tZjKRH7FrdvO0PI2iY5SMaKhCcBw1QXpQHSUxL6Hm-Wr8Q46gFAYoa6YffJV0Rx80FvJHmr1LMAA6PAF0dU_DzNdRVHdXm14t_nbfl-6xb6o7WQN259moUhkT1ZQ9CZsYwWvn7VBmpjfIXNJvIu0FDnRaHnNMrj3uN77_cAMdO3OcyCuy-CAKJ9c-0PxKToStb9juGSNa9ClpVQPADzpUxFqxZU029AXBPavXQK2Ezvy7YT4FwCkL8TEf5AnB5hfOZ5YCBlqD30n2heMdHDbXRHpxeaQB4aoY_6uSpJ3cPazBDsbvGi4fV2-0g5NvoTGgJUXa5p4UntRmuiJ2tZHbMmEjXzf-GV6QtTFIhseKsS3n6TMX68yqQOhYOzxvHdJXPjYxvjmm6-vJw5w2FDgiEXoQJQ7qaSmGzRwOA_cE4VBV_RhzrZELmp3A

    Response like this:

    Key Value
    Response HTTP/1.1 200 OK
    Content-Type application/json; charset=utf-8
    Server Kestrel
    X-SourceFiles =?UTF-8?B?QzpcVXNlcnNcUm9iZXJ0XERlc2t0b3BcSEJFIE1hbmFnZXJcTUFJTlxCbHVlem9uZSBXZWJBcGlcc3JjXEJ6LkFwcGxpY2F0aW9uXEJ6LkFwcGxpY2F0aW9uLkFwaVx3d3dyb290XGFwaVxhY2NvdW50XElzTG9nZ2VkSW4=?=
    X-Powered-By ASP.NET
    Access-Control-Allow-Methods GET,PUT,POST,DELETE
    Access-Control-Allow-Headers Content-Type,x-xsrf-token,X-ACL-Key
    Date Fri, 06 May 2016 14:23:22 GMT
    Content-Length 68

    CHROME

    My request to Login web api looks like this:

    POST /api/account/Login HTTP/1.1
    Host: localhost:44338
    Connection: keep-alive
    Content-Length: 246
    Accept: */*
    Origin: https://localhost:44356
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
    X-ACL-Key: 4A6F0007-95E7-4423-B786-6FBF981799FE
    Referer: https://localhost:44356/
    Accept-Encoding: gzip, deflate
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

    Response like this:

    HTTP/1.1 200 OK
    Cache-Control: no-cache
    Pragma: no-cache
    Content-Type: application/json; charset=utf-8
    Expires: -1
    Vary: Origin
    Server: Kestrel
    Set-Cookie: oAuthInterop=CfDJ8Asqo6qO2cNHlXpsdNLsuoRvlRjfUBWrkt3W3NzBJIoFYA6DcQivnfYmZV2O5xuiqpd75oRjZ-JeHBcjiOK0HoFJQ9f61RyJ2HDeuCNmQk0H-pA3Lzs5ft_F49dpQt0kFn3_-FzEh5-NScCbY4N6TiuYlWY4VSoKsdJJ91k7Z4LQO-0Wm3cZ6HfX0E6pLzGG4lWaZGuV-gOsVCRygR5nv_O_YpWwfaLsT_51aX6fNXVSotU6MECEkFdfWseqOGyYVj7KJrxY2mPwksE0XGACs12TnmfJzCABrzd06FnTPy3RuqJF2IWOobX6ZAHGMoAVFR07mhy9gMPyaHQ12RKmhBhZSXE-Yi3BHow2ER9d2Niligx7JjwYR7UfHFHWJdoYzewLRkZZGE5pw67O710hYyA2UCM2ODB9l9x-WDQ1A_3xjxu2Mrkp0lrF0V-h3y6V2gzEP9RyQAjDISEEZQqvb-GzfZrsRzzQcMn0TMhq5_LUKkX3AScSGRiarBzZ2O9Af3jzwTmN1BciJknJwMKRefq_zrXH7kymCD1kJM89aGkswqp2bycMQjlsjqg5k8EEhv8u1kLA7hA9NyE2ZaamB1PAWYz4NXi3Agccgw83nFi4bs6VE8ZLnyZFEwxdyEGyvQ; path=/; secure; httponly
    Access-Control-Allow-Origin: https://localhost:44356
    Access-Control-Allow-Credentials: true
    X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcUm9iZXJ0XERlc2t0b3BcSEJFIE1hbmFnZXJcTUFJTlxCbHVlem9uZSBXZWJBcGlcc3JjXEJ6LkFwcGxpY2F0aW9uXEJ6LkFwcGxpY2F0aW9uLkFwaVx3d3dyb290XGFwaVxhY2NvdW50XExvZ2lu?=
    X-Powered-By: ASP.NET
    Access-Control-Allow-Methods: GET,PUT,POST,DELETE
    Access-Control-Allow-Headers: Content-Type,x-xsrf-token,X-ACL-Key
    Date: Fri, 06 May 2016 12:59:36 GMT
    Content-Length: 16

    Subsequent test web api call (IsLoggedIn):

    GET /api/account/IsLoggedIn HTTP/1.1
    Host: localhost:44338
    Connection: keep-alive
    Accept: */*
    Origin: https://localhost:44356
    User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
    X-ACL-Key: 4A6F0007-95E7-4423-B786-6FBF981799FE
    Referer: https://localhost:44356/
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

    Response like this:

    HTTP/1.1 401 Unauthorized
    Content-Length: 0
    Content-Type: text/plain; charset=utf-8
    Server: Kestrel
    X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcUm9iZXJ0XERlc2t0b3BcSEJFIE1hbmFnZXJcTUFJTlxCbHVlem9uZSBXZWJBcGlcc3JjXEJ6LkFwcGxpY2F0aW9uXEJ6LkFwcGxpY2F0aW9uLkFwaVx3d3dyb290XGFwaVxhY2NvdW50XElzTG9nZ2VkSW4=?=
    X-Powered-By: ASP.NET
    Access-Control-Allow-Methods: GET,PUT,POST,DELETE
    Access-Control-Allow-Headers: Content-Type,x-xsrf-token,X-ACL-Key
    Date: Fri, 06 May 2016 12:59:43 GMT

    My web api controller code looks like this:

    [Authorize]
    [EnableCors("AllowAll")]
    [Route("api/[controller]")]
    public class AccountController : Controller
    {
    	private readonly UserManager<ApplicationUser> _userManager;
    	private readonly SignInManager<ApplicationUser> _signInManager;
    
    	public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    	{
    		_userManager = userManager;
    		_signInManager = signInManager;
    	}
    	
    	[HttpPost("login")]
    	[AllowAnonymous]
    	public async Task<IActionResult> Login(UserLogin model)
    	{
    		if (ModelState.IsValid) {
    			var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
    
    			if (result.Succeeded) {
    				return Json(new { success = true });
    			}
    			if (result.RequiresTwoFactor) {
    				return Json(new { success = false, errType = 1 });
    			}
    			if (result.IsLockedOut) {
    				return Json(new { success = false, errType = 2 });
    			} else {
    				ModelState.AddModelError(string.Empty, "Invalid login attempt.");
    				return Json(new { success = false, errType = 3 });
    			}
    		}
    
    		return Json(new { success = false, errType = 0 });
    	}
    
    	[HttpGet("IsLoggedIn")]
    	public IActionResult IsLoggedIn()
    	{
    		return Json(new {
    			loggedon = (HttpContext.User.Identity.Name != null && HttpContext.User.Identity.IsAuthenticated),
    			isauthenticated = HttpContext.User.Identity.IsAuthenticated,
    			username = HttpContext.User.Identity.Name
    		});
    	}
    }

    Startup.cs for my web api looks like this: 

        public class Startup
        {
            public static int SessionLength { get; private set; }
            private string Connection;
    
            public Startup(IHostingEnvironment env)
            {
                // Set up configuration sources.
                var builder = new ConfigurationBuilder()
                    .AddJsonFile("appsettings.json")
                    .AddEnvironmentVariables();
                Configuration = builder.Build();
    
                SessionLength = 30;
            }
    
            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)
            {
                // Get the configured connection string.
                Connection = Configuration["Data:DefaultConnection:ConnectionString"];
    
                var userStore = new CustomUserStore();
                var roleStore = new CustomRoleStore();
                var userPrincipalFactory = new CustomUserPrincipalFactory();
    			
                services.AddInstance<IUserStore<ApplicationUser>>(userStore);
                services.AddInstance<IRoleStore<ApplicationRole>>(roleStore);
                services.AddInstance<IUserClaimsPrincipalFactory<ApplicationUser>>(userPrincipalFactory);
    
                services.AddIdentity<ApplicationUser, ApplicationRole>(options => {
                    options.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents() {
                        OnRedirectToAccessDenied = ctx =>
                        {
                            if (ctx.Response.StatusCode == (int)HttpStatusCode.Unauthorized || ctx.Response.StatusCode == (int)HttpStatusCode.Forbidden) {
                                return Task.FromResult<object>(null);
                            }
                            ctx.Response.Redirect(ctx.RedirectUri);
                            return Task.FromResult<object>(null);
                        },
                        OnRedirectToLogin = ctx =>
                        {
                            if (ctx.Response.StatusCode == (int)HttpStatusCode.Unauthorized || ctx.Response.StatusCode == (int)HttpStatusCode.Forbidden) {
                                return Task.FromResult<object>(null);
                            }
                            ctx.Response.Redirect(ctx.RedirectUri);
                            return Task.FromResult<object>(null);
                        }
                    };
    
                    //options.Cookies.ApplicationCookie.CookieHttpOnly = false;
                    options.Cookies.ApplicationCookieAuthenticationScheme = "ApplicationCookie";
                    options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie";
                    options.Cookies.ApplicationCookie.CookieName = "oAuthInterop";
                    options.Cookies.ApplicationCookie.AutomaticChallenge = true;
                    options.Cookies.ApplicationCookie.AutomaticAuthenticate = true;
                    options.Cookies.ApplicationCookie.DataProtectionProvider = new DataProtectionProvider(new DirectoryInfo("d:\\development\\artefacts"),
                        configure =>
                        {
                            configure.SetApplicationName("TestAuthApp");
                            //configure.ProtectKeysWithCertificate("thumbprint");
                        });
                    options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromMinutes(SessionLength);
    
                }).AddDefaultTokenProviders();
    
                // Add framework services.
                services.AddMvc();
                
                // Add cross site calls.
                //TODO: implement with better security instead of allowing everything through.
                services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
                                                                                .AllowAnyMethod()
                                                                                .AllowAnyHeader().AllowCredentials()));
            }
    
            // 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();
    
                app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
    
                app.UseStaticFiles();
                
                app.UseIdentity();
    
                app.UseMvc();
    
            }
    	}





    • Edited by rmccabe82 Friday, May 6, 2016 2:43 PM
    • Moved by CoolDadTx Friday, May 6, 2016 3:39 PM ASP.NET related
    Friday, May 6, 2016 2:25 PM

All replies