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");
});
...
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.