Getting SameSite cookie issues with Azure AD authentication with downstream WebAPI

1.6k views Asked by At

I added support in my Blazor Server app for downstream API in which I send an access token to the API. This caused the authentication against Azure AD to stop working, by giving me cookies that chrome refuses due to SameSite policy (it does authenticate, but can't save the cookie). It works fine from localhost, but not at all in Azure. The warning I get in Chrome is:

A cookie associated with a cross-site resource at https://---snip---.azurewebsites.net/ was set without the SameSite attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

(from uri: https://login.microsoftonline.com/98f2d82c-c037-4c5f-a381-074c1428381c/reprocess?ctx=...)

The only code I can think of that would give me this issue is the following, which retrieves the access token, and handles the exception in Blazor. This code is from here:

https://github.com/AzureAD/microsoft-identity-web/wiki/Managing-incremental-consent-and-conditional-access

private async Task<string> GetAccessToken(string[] requiredScopes)
{
    string[] scopes = requiredScopes ?? _configuration["DownstreamAPI:Scopes"]?.Split(' ');

    string accessToken = null;
    try
    {
        accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
    }
    catch (Exception ex)
    {
        _consentHandler.HandleException(ex);
    }

    return accessToken;
}

My Startup.cs:

using Blazored.Modal;
using Airline.CAM.WebUI.Utility;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using System.Net.Http;
using Microsoft.AspNetCore.Http;

namespace Airline.CAM.WebUI
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
        {
            Configuration = configuration;
            WebHostEnvironment = webHostEnvironment;
        }

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment WebHostEnvironment { get; set; }

        // 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<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                options.HandleSameSiteCookieCompatibility();
            });

            services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
            {
                options.TokenValidationParameters.RoleClaimType = "roles";
                options.NonceCookie.SameSite = SameSiteMode.None;
            });

            var scopes = new[] { "api://---snip---/Cam_access_as_user" };
            services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
                .EnableTokenAcquisitionToCallDownstreamApi(scopes)
                .AddInMemoryTokenCaches();

            services.AddMicrosoftGraph(scopes, "https://graph.microsoft.com/v1.0");

            if (!WebHostEnvironment.IsDevelopment())
            {
                services.AddSignalR().AddAzureSignalR(options =>
                {
                    options.ServerStickyMode = Microsoft.Azure.SignalR.ServerStickyMode.Required;
                });
            }

            services.AddControllersWithViews(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            }).AddMicrosoftIdentityUI();

            services.AddScoped<JsConsole>();
            services.AddScoped<HttpClient>();
            services.AddScoped<Utility.DownstreamWebApi>();
            services.AddScoped<ApiHelper>();
            services.AddRazorPages();
            services.AddServerSideBlazor(o => o.DetailedErrors = true).AddMicrosoftIdentityConsentHandler();
            services.AddBlazoredModal();

            services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"]);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }
            app.UseExceptionHandler("/Error");
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}
0

There are 0 answers