dockerduendeidentityserver6

Error configuring Duende IdentityServer 6 with Docker


I've been fighting with a problem for some days. It's related to connecting containers using Duende IdentityServer as IdP.

My system consists of:

The application must run in HTTP and in front of it I will have a balancer with TLS, so internally it must use HTTP.

I've created a docker compose file to run the application using this configuration (simplify version):

services:
  idp:
    build: ./<Identity-folder>
    ports:
      - "5000:80"
    environment:
      - ...
  cli:
    build: ./<Client-folder>
    ports:
      - "5002:80"
    environment:
      - AUTHORITY=http://idp
      - REQUIREHTTPSMETADATA=false

When I hit login from the client app I get the following error:

cli-1  | warn: Microsoft.AspNetCore.Http.ResponseCookies[1]
cli-1  |       The cookie '.AspNetCore.OpenIdConnect.Nonce.CfDJ8F-b95I6wSdJpaLTwuHEFX_Az_Khhb2aOJ7MvLT7345b_zt-x9cVcuNtMmP6mAWRwuExmttQyom3HinNzSetJ19_I766jjXwwT4S9mdj9uj1qlrnd_fxy401UYZmdIwak7aeuoC5Re98QlcaH5V48Uahv_Hcvo6RjQEEigx9eCqY-UM3oBAuVA2nLhvxt8W1KV6WS9lvN2TeL1jVzZrSuCXAj7nJAvlgT1ovdTxN_3K4_m3Q60kYrrceGCz8RYhiftDLF5yNGIsDssQHFz0ReBo' has set 'SameSite=None' and must also set 'Secure'.
cli-1  | warn: Microsoft.AspNetCore.Http.ResponseCookies[1]
cli-1  |       The cookie '.AspNetCore.Correlation.yYUba7j9MG6EzwnzfS00gE9OOov4yFFE742naXtZFoY' has set 'SameSite=None' and must also set 'Secure'.

The relevant configuration in program.cs of the IdP is as follows:

...
builder.Services.AddRazorPages();

var cert = SigningCredentialConfiguration.GetFromFile(gConfig);

builder.Services
    .AddIdentityServer(options =>
    {
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;

        options.EmitStaticAudienceClaim = true;

        options.KeyManagement.Enabled = false;

        options.Authentication.CheckSessionCookieSameSiteMode = SameSiteMode.Strict;
    })
    .AddInMemoryIdentityResources(InMemoryConfig.IdentityResources)
    .AddInMemoryApiScopes(InMemoryConfig.ApiScopes)
    .AddInMemoryClients(InMemoryConfig.Clients)
    .AddAspNetIdentity<AppUser>()
    .AddSigningCredential(cert);
...

The InMemoryConfig.Clients is as follows:

...
new Client
{
    ClientId = "client",
    ClientSecrets = { new Secret("secret".Sha256()) },

    AllowedGrantTypes = GrantTypes.Code,

    RedirectUris = { "http://localhost:5002/signin-oidc", "http://cli/signin-oidc" },
    FrontChannelLogoutUri = "http://localhost:5002/signout-oidc",
    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

    AllowOfflineAccess = true,
    AllowedScopes = { "openid", "profile", ... },
    AllowPlainTextPkce = true,
},
...

And the program.cs of the client app is as follows:

...
builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = "cookie";
        options.DefaultChallengeScheme = "oidc";
        options.DefaultSignOutScheme = "oidc";
    })
    .AddCookie("cookie", options =>
    {
        options.Cookie.Name = "__Host-bff";
        options.Cookie.SameSite = SameSiteMode.Strict; // Strict

        options.Cookie.SecurePolicy = CookieSecurePolicy.None;
        options.Cookie.IsEssential = true;
    })
    .AddOpenIdConnect("oidc", options =>
    {
        options.Authority = gConfig.Authority;
        options.RequireHttpsMetadata = gConfig.RequireHttpsMetadata;

        options.ClientId = "client";
        options.ClientSecret = "secret";
        options.ResponseType = "code";
        options.ResponseMode = "query";
      
        options.GetClaimsFromUserInfoEndpoint = true;
        options.MapInboundClaims = false;
        options.SaveTokens = true;

        options.Scope.Clear();
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("offline_access");
    });
...

Solution

  • You must use strict for the session cookie because it was "set" by a different site (IdentityServer). You need to use LAX.

      options.Cookie.SameSite = SameSiteMode.Strict; // Strict
    

    Also, cookies won't work if you use HTTP; you must use HTTPS for successful OIDC in the browser.

    As an update to my answer, I have just written a blog post about this problem: IdentityServer in Docker Containers.