Cookies not saved between browser sessions on iOS Safari
Asked Answered
O

2

13

I have an MVC 4 website where a user can login and I save a cookie with their session information so they don't have to login again.

public void SetCookie(HttpCookie cookie)
{
    HttpContext.Current.Response.Cookies.Set(cookie);
}

This works on desktop devices, but when I run this on iOS, it doesn't work 100% of the time. If I leave at least 1 page open in the mobile browser (either Chrome or Safari), and navigate back to my site, my session cookie is found and I don't have to login. But if I close ALL windows of that browser, then the next time I navigate back to my site, the session cookie is not found. I'm setting a 1 year duration/expiration on my cookie so it's not expiring.

The only thing I've found so far is that this is a bug in .NET 4.0 and is fixed in .NET 4.5. I believe I'm already running .NET 4.5, by looking at my *.csproj and the TargetFrameworkVersion element:

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>
    </ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{xxxxxxxxxxxxxxxxxx}</ProjectGuid>
    <ProjectTypeGuids>{xxxxxxxx};{xxxxxxxxxxxxx};{xxxxxxxxxxxxxxxx}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>MyApp</RootNamespace>
    <AssemblyName>MyApp</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <MvcBuildViews>false</MvcBuildViews>
    <UseIISExpress>true</UseIISExpress>
    <IISExpressSSLPort />
    <IISExpressAnonymousAuthentication />
    <IISExpressWindowsAuthentication />
    <IISExpressUseClassicPipelineMode />
  </PropertyGroup>

Is this a bug with .NET (or MVC), or is it my coding? Do I need to upgrade to MVC 5 (instead of the original recommendation of upgrading to .NET 4.5)?

This has really been bugging me since the majority of the traffic to my site in the next coming months will be from mobile users, and I'll probably lose some of them if they have to keep logging in everytime (I know I hate having to login on a mobile device...)

Edit:

Btw - Here's another page on the same subject: Asp.Net Forms Authentication when using iPhone UIWebView

And I've also tried implementing this and it didn't work either:

http://www.bloggersworld.com/index.php/asp-net-forms-authentication-iphone-cookies/

And the above includes Scott Hanselmans suggested fix:

http://www.hanselman.com/blog/FormsAuthenticationOnASPNETSitesWithTheGoogleChromeBrowserOnIOS.aspx

Here's my cookie creation code, in case it helps:

private void CreateAndSetAuthenticationCookie(int loginId, string username)
    {
        HttpCookie cookie = CreateAuthenticationCookie(loginId, username);

        _cookieService.SetCookie(cookie);
    }

    private HttpCookie CreateAuthenticationCookie(int loginId, string username)
    {
        string userData = string.Format("loginId:{0},username:{1}", loginId, username);
        var ticket = new FormsAuthenticationTicket(loginId, username, DateTime.Now, DateTime.Now.AddYears(1), false, userData, FormsAuthentication.FormsCookiePath);
        string encryptedTicket = FormsAuthentication.Encrypt(ticket);

        return new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    }

One thing that I pointed out in my comments, I have "PersistentCookie" set to false....not sure if that makes a difference, I'll do more research.

Update:

First of all, the PersistentCookie is set to true now, and that did not have any changes on the behavior.

One of the commentors below suggested that I run Fiddler while accessing the website from iPhone. After going through the very short and easy steps to get that setup, here's what I found out.

The first request I tried pointed out (I believe) what the actual problem is. When I examined that first request, iOS Safari is sending a DNT header. Having no idea what that was, I looked it up and it's a "Do Not Track" header.

Next, I went and checked my Safari settings to turn that off. Guess what, it's already off. Why the hell is Safari (iOS) sending a DNT header when the setting (Settings -> Safari -> Do Not Track) is not set? Also, the Block Cookies, which is right below it, is set to "Never".

After getting frustrated with that, I went to check on Chrome for iOS to see if that still doesn't work. IT WORKS! From what I can tell, I'd close all tabs, try again, close all tabs, then kill the browser, and it still works. Hooray!

Now, I need to figure out why iOS Safari is sending the DNT header...

Orjonikidze answered 16/7, 2014 at 13:8 Comment(16)
Wow, after two weeks, I've finally found this: bloggersworld.com/index.php/… but I'm too tired to try this tonight...will get to try it soon.Orjonikidze
Ugh, that was a no-go...Bueller????Orjonikidze
just a guess, but do you use an iframe? apple devices don't like 3rd party cookies which could be a problem.Bondholder
@Bondholder nope, no iframe's or any embedded type stuffOrjonikidze
@Bondholder Found this post about cookies and got me wondering, I have the "PersistentCookie" set to false, does that make a difference? #8852557Orjonikidze
Nope, didn't matter...Orjonikidze
let's start with some basic debugging... is the cookie actually disappearing or is it being sent to the server and the server ignores for some reason? look at the HTTP traffic to see exactly what is going back and forth over the wire. use fiddler for that. docs.telerik.com/fiddler/configure-fiddler/tasks/…Poler
Side note: be careful with usage of "session cookies" phrase - that may mean "session" as opposite of "persistent" or ASP.Net "session" cookie. May need clarification in the post.Displant
@RobertLevy How do I debug this when it only occurs on iPhone (for me), and my application is hosted on App Harbor (both test and Prod)? (Since I couldn't run Fiddler there) Is it possible to run a Development version on my machine at home, and have the iPhone point to that?Orjonikidze
if you follow those instructions, fiddler will let you see all HTTP/HTTPS traffic between your phone and the internetPoler
@RobertLevy my bad, I didn't check your link...Orjonikidze
@RobertLevy great. Now I see that the cookie is DNT, which is Do Not Track. I checked the settings for iOS on the device and Do Not Track is NOT checked. Is that coming from my site?Orjonikidze
another cause might be the IIS as it estimates browser capabilities #4159050Bondholder
@Bondholder I believe I've already tried that (was so long ago), but let me make sure tonight...Orjonikidze
@Bondholder I checked out your link regarding the "another cause might be the IIS..." comment and I've actually already implemented the browser files in my project, and that had no effect on this. I guess I'm still searching 4 months later...Orjonikidze
@Orjonikidze sorry to hear it didn't help... for now I am out of ideasBondholder
O
33

This is HORRIBLY embarrasing. I found out that I've had my iOS Safari browser in "Private Browsing Mode" FOR YEARS!

I feel like my "Software Developer" job title needs removed for awhile. Sorry for wasting everyone's time.

Orjonikidze answered 23/4, 2015 at 13:10 Comment(5)
To be honest and humble, great characteristicsTwentyfourmo
Might not be as embarassing as you think. It's kinda hard to tell at first glance.Semeiology
happens to everyone. If anyone says it doesn't, they don't really do any work.Inquiline
I had the same problem with setting cookies in Express and iOS. In Private mode Safari clears cookies for every new tab! Hope it helps for anybody.Fatwitted
My boss had been using Safari in private mode for at least a year now and complaining that sites aren't working properly... Thank you for your answer!Ringent
C
3

I think you answered your own question with persistent cookie. Regular cookies expire when the browser session ends (this is typically closing the browser). Persistent cookies have a date when they should be removed and can live across browser sessions.

Your code should look something like this:

private HttpCookie CreateAuthenticationCookie(int loginId, string username)
{
    string userData = string.Format("loginId:{0},username:{1}", loginId, username);
    var ticket = new FormsAuthenticationTicket(loginId, username, 
                         DateTime.Now, DateTime.Now.AddYears(1), 
                         false, userData, FormsAuthentication.FormsCookiePath);
    string encryptedTicket = FormsAuthentication.Encrypt(ticket);

    return new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket){{
         Expires = DateTime.Now.AddYears(1);
    }};
}

This way your cookie will persist across browser sessions for one year.

Carcajou answered 8/8, 2014 at 11:14 Comment(3)
I tried this already, (my comment "Nope, didn't matter"). I can try putting everything in the same method to see if that makes a difference though...(my version has the ticket in one method and the cookie in another)Orjonikidze
Using something like firebug/chrome dev tools, can you show what your cookie looks like to the client?Carcajou
I'm upvoting this answer, but not accepting because this only fixed iOS Chrome, NOT Safari.Orjonikidze

© 2022 - 2024 — McMap. All rights reserved.