10

How can I set the CookieDOmain in the CookieAuthenticationOptions at runtime if i want to pull this value from the Request.Url or from some settings stored in my database?

I want to support sub-domains, but also support multi-tenants too which each have different domains.

At the moment this is configured I don't have access to either of these.

Paul

Paul Hinett
  • 1,951
  • 2
  • 26
  • 40

4 Answers4

16

You can assign your own cookie provider:

CookieAuthProvider myProvider = new CookieAuthProvider();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
   AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
   LoginPath = new PathString("/Account/Login"),
   Provider = myProvider
});

Either implement your own, or simply inherit from the existing provider:

public class CookieAuthProvider : CookieAuthenticationProvider
{
    public override void ResponseSignIn(CookieResponseSignInContext context)
    {
      //Alter you cookie options
      //context.CookieOptions.Domain  =  "www...";      
      base.ResponseSignIn(context);
    }
 }

And implement ResponseSignIn, it is called when an endpoint has provided sign in information before it is converted into a cookie. By implementing this method the claims and extra information that go into the ticket may be altered.

You'll be passed a CookieResponseSignInContext, which exposes CookieOptions property that can be replaced or altered during the ResponseSignIn call.

Code references from Katana project:

MK.
  • 5,139
  • 1
  • 22
  • 36
  • 1
    The mentioned code is based on Owin 3.0.0-beta2-30422-012-dev, you may need to modify it if you are using an earlier version. – MK. Apr 22 '14 at 14:28
  • I tried this but I found that SignOut stopped working. Any thoughts? – Matt Jenkins Sep 24 '14 at 19:27
  • 2
    Do net get fooled as me. If you do not find `CookieOptions` property but instead you find an `Options` property, do not try using it, believing there is a typo on this answer. It is not the case. If you lack `CookieOptions` property, you have to update your Microsoft.Owin.Security.Cookies reference. Direct changes to `Options` property leads to bugs as it changes the manager options for subsequent requests but not for current one! Changes on `CookieOptions` property apply to current request, and only to it. – Frédéric Oct 22 '14 at 17:06
  • 3
    And you also have to override ResponseSignOut, otherwise you may be unable to sign out... As stated by @MattJenkins comment, but he made a typo and wrote `In` instead of `Out`. – Frédéric Oct 22 '14 at 17:33
  • @Frederic - Well spotted, I've deleted that comment! – Matt Jenkins Oct 22 '14 at 18:58
  • Unfortunately remains an issue : sliding expiration causes a cookie renewal which does not trigger any method on cookie provider. So it gets renewed without having a chance to alter its domain. – Frédéric Oct 27 '14 at 10:50
  • Yup, they should implement `ResponseRenew/CookieResponseRenewContext`. Another method would be to alter the cookie options itself using another middleware that is registered before cookies authentication! didn't test yet, but its worth trying .. – MK. Oct 28 '14 at 07:48
  • Something like `app.Use((context, next) => { cookieOptions.CookieDomain = "www"; return next.Invoke(); });` – MK. Oct 28 '14 at 08:00
  • @MK can you please add little more steps to help me. how do i assign context.CookieOptions.Domain = "www..."; from controller ? I tried this way but no luck https://stackoverflow.com/a/33308419/1386991 – Abhimanyu Apr 05 '18 at 13:12
  • @Abhimanyu I have no more steps other than this and the answer you linked to. – MK. Apr 05 '18 at 19:32
  • Remember to override ResponseSignOut too with the same code as ResponseSignIn or your sign out will stop working. – Javier Pallarés Jun 24 '21 at 10:41
4

Do you already try this:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
  AuthenticationType = "Application",
  LoginPath = "/Account/Login",
  CookieDomain = ".myDomain.com"
});
jomsk1e
  • 3,585
  • 7
  • 34
  • 59
  • 2
    It seems that the OP wants to do this dynamically, and not with a fixed value known in advance/not requiring changes by developer to deploy on a new domain. – pwdst Apr 17 '14 at 23:52
4

It looks like MK. answer does not allow proper handling of token renewal when using SlidingExpiration option.

As a workaround, instead of supplying a custom cookie provider, it appears you can supply a custom cookie manager, and define your own methods for adding/removing the cookie.

To keep it simple in my case, I reuse the default cookie manager under the hood. (I can not extend it, its methods are not overridable.)

Here is the code I have ended up with:

using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.DataProtection;
using Owin;

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var options = new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            SlidingExpiration = true,
            CookieManager = new CustomCookieManager()
        };

        app.UseCookieAuthentication(options);
    }
}

public class CustomCookieManager : ICookieManager
{
    private readonly ICookieManager ConcreteManager;

    public CustomCookieManager()
    {
        ConcreteManager = new ChunkingCookieManager();
    }

    string ICookieManager.GetRequestCookie(IOwinContext context, string key)
    {
        return ConcreteManager.GetRequestCookie(context, key);
    }

    void ICookieManager.AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        SetupDomain(context, options);
        ConcreteManager.AppendResponseCookie(context, key, value, options);
    }

    void ICookieManager.DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        SetupDomain(context, options);
        ConcreteManager.DeleteCookie(context, key, options);
    }

    private void SetupDomain(IOwinContext context, CookieOptions options)
    {
        // custom logic for assigning something to options.Domain
    }
}
Frédéric
  • 9,364
  • 3
  • 62
  • 112
0

For working in NET7, we need some updates of Frédéric code. Also I don't delete my custom logic, for share cookie between subdomains, maybe it will help smb. And also in my custom logic relized sharing cookie of Duende Identity Server (Identity Server 4 also must work).

using Duende.IdentityServer.Configuration;
using Microsoft.AspNetCore.Authentication.Cookies;

namespace IdentityServerForEt
{
    public class CustomCookieManager : ICookieManager
    {
        private readonly ICookieManager ConcreteManager;

        public CustomCookieManager()
        {
            ConcreteManager = new ChunkingCookieManager();
        }

        public string? GetRequestCookie(HttpContext context, string key)
        {
            return ConcreteManager.GetRequestCookie(context, key);
        }

        public void AppendResponseCookie(HttpContext context, string key, string? value, CookieOptions options)
        {
            SetupDomain(context, options);
            ConcreteManager.AppendResponseCookie(context, key, value, options);
        }

        public void DeleteCookie(HttpContext context, string key, CookieOptions options)
        {
            SetupDomain(context, options);
            ConcreteManager.DeleteCookie(context, key, options);
        }

        private static void SetupDomain(HttpContext context, CookieOptions options)
        {
            var hostParts = context.Request.Host.Value.Split('.');
            string? domain = null;
            if (hostParts.Length > 2)
                domain = string.Join('.', hostParts.TakeLast(2));
            options.Domain = domain;
            if (domain != null)
            {
                var identityServerOption = context.RequestServices.GetService<IdentityServerOptions>();
                if (identityServerOption != null)
                    identityServerOption.Authentication.CheckSessionCookieDomain = domain;
            }
        }
    }
}