question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

CookiePolicyOptions not applied to OpenIdConnect Cookies

See original GitHub issue

Hey,

I have an implementation using OpenIdConnect for authentication process including a separate Authentication server ( idsrv4). They authentication worked so far until the changes of the default cookie policy of browser. Cause of this i wanted to implement the recommend Solution for the cookie SameSite changes (Recommendation)

After i added the implementation and tested the result i always ended with a redirect loop between my application server and authentication server caused by blocked of the Nonce and correllation cookie of Google Chrome. After i changed the cookie samesite manually to Unspecified in the options of OpenIdConnect everything worked.

I am not sure if this is an issue or if this implementation was made by intention but why are the CookiePolicyOptions not applied to the open id connect cookies ? Couldn’t this cause problems on older browsers?

The extension for the cookie policy options and related handler ( almost the same as the recommendation at the moment). The ConfigureNonbreakingSameSiteCookies Method is the first method called in the startup.cs

    public static class SameSiteCookieServiceCollectionExtensions
    {
        /// <summary>
        /// -1 defines the unspecified value, which tells ASPNET Core to NOT
        /// send the SameSite attribute. With ASPNET Core 3.1 the
        /// <seealso cref="SameSiteMode" /> enum will have a definition for
        /// Unspecified.
        /// </summary>
        private const SameSiteMode Unspecified = SameSiteMode.Unspecified;

        /// <summary>
        /// Configures a cookie policy to properly set the SameSite attribute
        /// for Browsers that handle unknown values as Strict. Ensure that you
        /// add the <seealso cref="Microsoft.AspNetCore.CookiePolicy.CookiePolicyMiddleware" />
        /// into the pipeline before sending any cookies!
        /// </summary>
        /// <remarks>
        /// Minimum ASPNET Core Version required for this code:
        ///   - 2.1.14
        ///   - 2.2.8
        ///   - 3.0.1
        ///   - 3.1.0-preview1
        /// Starting with version 80 of Chrome (to be released in February 2020)
        /// cookies with NO SameSite attribute are treated as SameSite=Lax.
        /// In order to always get the cookies send they need to be set to
        /// SameSite=None. But since the current standard only defines Lax and
        /// Strict as valid values there are some browsers that treat invalid
        /// values as SameSite=Strict. We therefore need to check the browser
        /// and either send SameSite=None or prevent the sending of SameSite=None.
        /// Relevant links:
        /// - https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1
        /// - https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
        /// - https://www.chromium.org/updates/same-site
        /// - https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
        /// - https://bugs.webkit.org/show_bug.cgi?id=198181
        /// </remarks>
        /// <param name="services">The service collection to register <see cref="CookiePolicyOptions" /> into.</param>
        /// <returns>The modified <see cref="IServiceCollection" />.</returns>
        public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
        { 
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.MinimumSameSitePolicy = Unspecified;
                options.OnAppendCookie = cookieContext =>
                   CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
                options.OnDeleteCookie = cookieContext =>
                   CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
            });

            return services;
        }

        private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
        {
            if (options.SameSite == SameSiteMode.None)
            {
                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
                if (DisallowsSameSiteNone(userAgent))
                {
                    options.SameSite = Unspecified;
                }
            }
        }

        /// <summary>
        /// Checks if the UserAgent is known to interpret an unknown value as Strict.
        /// For those the <see cref="CookieOptions.SameSite" /> property should be
        /// set to <see cref="Unspecified" />.
        /// </summary>
        /// <remarks>
        /// This code is taken from Microsoft:
        /// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
        /// </remarks>
        /// <param name="userAgent">The user agent string to check.</param>
        /// <returns>Whether the specified user agent (browser) accepts SameSite=None or not.</returns>
        private static bool DisallowsSameSiteNone(string userAgent)
        {
            // Cover all iOS based browsers here. This includes:
            //   - Safari on iOS 12 for iPhone, iPod Touch, iPad
            //   - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
            //   - Chrome on iOS 12 for iPhone, iPod Touch, iPad
            // All of which are broken by SameSite=None, because they use the
            // iOS networking stack.
            // Notes from Thinktecture:
            // Regarding https://caniuse.com/#search=samesite iOS versions lower
            // than 12 are not supporting SameSite at all. Starting with version 13
            // unknown values are NOT treated as strict anymore. Therefore we only
            // need to check version 12.
            if (userAgent.Contains("CPU iPhone OS 12")
               || userAgent.Contains("iPad; CPU OS 12"))
            {
                return true;
            }

            // Cover Mac OS X based browsers that use the Mac OS networking stack.
            // This includes:
            //   - Safari on Mac OS X.
            // This does not include:
            //   - Chrome on Mac OS X
            // because they do not use the Mac OS networking stack.
            // Notes from Thinktecture: 
            // Regarding https://caniuse.com/#search=samesite MacOS X versions lower
            // than 10.14 are not supporting SameSite at all. Starting with version
            // 10.15 unknown values are NOT treated as strict anymore. Therefore we
            // only need to check version 10.14.
            if (userAgent.Contains("Safari")
               && userAgent.Contains("Macintosh; Intel Mac OS X 10_14")
               && userAgent.Contains("Version/"))
            {
                return true;
            }

            // Cover Chrome 50-69, because some versions are broken by SameSite=None
            // and none in this range require it.
            // Note: this covers some pre-Chromium Edge versions,
            // but pre-Chromium Edge does not require SameSite=None.
            // Notes from Thinktecture:
            // We can not validate this assumption, but we trust Microsofts
            // evaluation. And overall not sending a SameSite value equals to the same
            // behavior as SameSite=None for these old versions anyways.
            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6") || userAgent.Contains("Chrome/8"))
            {
                return true;
            }

            return false;
        }
    }

Registration of the authentication services:

  services.AddAuthentication(options =>
           {
               options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
               options.DefaultChallengeScheme = "oidc";

           }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
           {
               options.EventsType = typeof(TokenValidator);

           })
           .AddOpenIdConnect("oidc", options =>
           {
               options.RequireHttpsMetadata = false;

               //These two options finally made the browser accepting the cookie
               options.CorrelationCookie.SameSite = AspNetCore.Http.SameSiteMode.Unspecified;
               options.NonceCookie.SameSite = AspNetCore.Http.SameSiteMode.Unspecified;

               options.NonceCookie.Expiration = TimeSpan.FromMinutes(5);

               options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
               options.GetClaimsFromUserInfoEndpoint = true;
               options.SaveTokens = true;

               ...
});

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
Tratchercommented, Jul 29, 2020

You’re missing the call to UseCookiePolicy, between UseForwardedHeaders and UseAuthentication looks like a good place for it.

0reactions
haukevlcommented, Aug 3, 2020

Works fine. Missed that point of the configuration for the application server. Thank you !

Read more comments on GitHub >

github_iconTop Results From Across the Web

Cookies added in an OpenIdConnect middleware ...
So I am using OpenId Connect and the AddOpenIdConnect configuration method to setup Authentication with Auth0. I have fully tested it locally ...
Read more >
Work with SameSite cookies in ASP.NET Core
The SameSite=Lax setting works for most application cookies. Some forms of authentication like OpenID Connect (OIDC) and WS-Federation ...
Read more >
Supporting legacy browsers and SameSite cookies without ...
In this post I explore one way to get ASP.NET Core Identity SameSite cookies working with both legacy and modern browsers.
Read more >
Beware of SameSite cookie policy in ASP.NET Core and ...
I have recently stumbled across a bug in iOS 12 preview which sort of breaks existing sites which make use of OpenID Connect...
Read more >
Implement Cookie Authentication in ASP.NET Core
This article will get you started with implementing cookie authentication in ASP.NET Core (without using Identity) applications.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found