3 minute read

I have recently stumbled across a bug in iOS 12 preview which sort of breaks existing sites which make use of OpenID Connect middleware in ASP.NET Core 2.1.

As iOS is coming closer to release, I decided to install it on my iPad for testing. After trying to access some our company's internal sites I always ended up in a redirect loop - basically AAD > site > AAD > site etc. - unending.

After doing some research and borrowing my friend's MacBook for debugging the browser in iOS - I noticed that the browser was not persisting cookies from our site. After going a bit further, I also tried other sites - Microsoft's https://admin.teams.microsoft.com for example which ended up with the same issue.

After that, I have done some research with the cookie configuration and the result has surfaced - the SameSite policy in Cookie Authentication middleware! The default configuration of Cookie Authentication's cookie is setting it to lax which means that the browser will not accept cookies from the site if it was redirected by POST request to it.

SameSite policy is another measure at the browser's level to fight CSRF attacks. So now since we have the root cause, what can we do about it?

In order for your ASP.NET Core 2.1 application to work with iOS 12, you need to configure CookiePolicyOptions along with the Cookie.SameSite policy as well:

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
     .AddAzureAD(options => Configuration.Bind("AzureAd", options))
     .AddCookie(options => options.Cookie.SameSite = SameSiteMode.None);
// ...
app.UseCookiePolicy(new CookiePolicyOptions
{
   MinimumSameSitePolicy = SameSiteMode.None
});

After that, your site is going to work again on iOS 12 again. I went to make some research and found out that other major browsers implement the SameSite cookie policy as well, however I couldn't reproduce the same issue there. Which made me wonder whether they are doing some sort of magic there or something is broken in iOS 12 so I went ahead and submitted a bug report to WebKit. After couple of hours of waiting, Apple engineers reachead out and I provided them with credentials to reproduce the issue.

So far, I haven't heard back from them yet, however this issue is still present in iOS 12 Developer Preview 11 as of now. I am going to update this post if new info becomes available.

Update 28SEP2018:
You can alternatively set the response mode to send the response in the query instead of the post body like so:

.AddOpenIdConnect("AzureAD", options => {
    ...
    // Set response type to code and response type to query
    // to avoid the default response_mode=form_post
    // which causes issues with WebKit's handling of samesite=lax for the session cookie
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.ResponseMode = OpenIdConnectResponseMode.Query;
};

Just beware that with this solution you won't receive the user's id_token directly and if you are using ADAL to redeem the authorization code for tokens, you might run into issues.

Comments

Fred

Thanks for writing this up! After running into the same issue, I went down a rabbit hole trying to see if the issue was related to ITP 2.0, and came up with nothing.

Disabling the SameSite property is a quick (but less secure) fix. Hopefully the WebKit folks can prioritize this issue and resolve it soon.

Mark C

Tried this and still stuck in a redirect loop when using Safari - can’t work out how to implement setting the response mode to send the response in the query as I am using the AddAzureAD method and adding AddOpenIdConnect(“AzureAD”) gives an error. Any tips please?

Jan Hajek

Great question! You are likely using the bits from https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/ package? If so, you need to register CookieAuthenticationOptions into the DI container before calling AddAzureAD. With the CookieAuthenticationOptions you can configure the cookie SameSite policy and it should work just fine. Please do let me know if it worked for you or not.

AddAzureAD source for reference: https://github.com/aspnet/AADIntegration/blob/master/src/Microsoft.AspNetCore.Authentication.AzureAD.UI/AzureADAuthenticationBuilderExtensions.cs#L120

Mark C

Hey Jan, really appreciate your help! Unfortunately changing the order of the DI didn’t make a difference - I’m sure it’s just me not following properly. My Startup.cs is here https://dotnetfiddle.net/mYKgYG

Kyle

I’m also wondering how to do this as I am having the same problem. I’ve tried what you have above and it does not work. It will still go into a redirect loop on ios 12.

Jan Hajek

Well, you seem to be missing adding CookieAuthenticationOptions into the DI like I mentioned above. SameSite policy only sets the minimum value. You also need to specify the actual value for CookieAuthentication SameSite policy.

rhys williams

Don’t forget the set the SameSite policy on your session cookies as well!

            services.AddSession(
                options =>
                    {
                        options.Cookie.SameSite = SameSiteMode.None;
                    });
nrgrts

that did it! services.addcookie and services.addsession both had to be updated. Confirmed working on core 2, iOS12 in March 2019.

Sundher

I tried all the above options. Still samesite not working in Safari 12. I am using Asp .Net Core 2.1 with Angular SPA template. Any help??

JustMe

Guess what! :

https://www.chromium.org/updates/same-site/incompatible-clients

Versions of Safari and embedded browsers on MacOS 10.14 and all browsers on iOS 12. These versions will erroneously treat cookies marked with SameSite=None as if they were marked SameSite=Strict. This bug has been fixed on newer versions of iOS and MacOS.

Why isn’t that company selling apples? They surely can’t write software…

Sarah

I tried the above options. Still samesite not working in Safari. I am using Asp .Net Core 3.1 with React SPA template. Both frontend and backend deployed independently. If I am not wrong, I need to make these changes on frontend which is build using (ASP.NET Core app with React js template). Any help would be appreciated.

To submit comments, go to GitHub Discussions.