Custom claims are not kept after 15 minutes

Jaime Stuardo 56 Reputation points
2022-01-05T13:36:19.237+00:00

is in Hello,

I developed an ASP.NET MVC application which uses ASP.NET Identity 2 and OWIN to provide authentication.

All works perfectly but authentication after I changed cookie duration to 30 days (it was 15 minutes before, the default).

I have this in Startup.Auth.cs file:

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            ExpireTimeSpan = TimeSpan.FromDays(30),
            SlidingExpiration = true,
            Provider = new CookieAuthenticationProvider
            { 
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            },
            CookieName = "ExampleName",
            CookieDomain = ".example.cl"
        }); 

Just after user was authencated, I add some claims, this way:

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            if (manager == null)
                return null;

            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie).ConfigureAwait(false);

            var nombre = string.Concat(this.FirstName, " ", this.LastName).Trim();
            if (string.IsNullOrEmpty(nombre))
            {
                var regexp = new System.Text.RegularExpressions.Regex("([^@]+)");
                var matches = regexp.Matches(this.Email);
                if (matches.Count > 0)
                    nombre = matches[0].Value;
                else
                    nombre = "Sin nombre";
            }

            var email = this.Email;
            if (string.IsNullOrEmpty(email))
                email = "No definido";

            userIdentity.AddClaim(new Claim(ClaimTypes.GivenName, nombre));
            userIdentity.AddClaim(new Claim(ClaimTypes.Email, email));
            foreach(var roleName in this.RoleNames)
                userIdentity.AddClaim(new Claim("Roles", roleName));

            userIdentity.AddClaim(new Claim(Helpers.Constantes.ClienteTrabajoNombre, this.CustomerName ?? string.Empty));
            userIdentity.AddClaim(new Claim(Helpers.Constantes.ClienteTrabajoId, this.CustomerId.ToString()));

            userIdentity.AddClaim(new Claim(Helpers.Constantes.ClienteAsignadoId, this.CustomerId.ToString()));

            // Si sólo hay una empresa asociada, debe ser la empresa seleccionada por defecto. -1 indica que no hay selección.
            if (this.CompanyIds.Count == 1)
            {
                userIdentity.AddClaim(new Claim(Helpers.Constantes.EmpresaTrabajoId, this.CompanyIds[0].ToString()));
                userIdentity.AddClaim(new Claim(Helpers.Constantes.EmpresaTrabajoNombre, this.CompanyNames[0].ToString()));
            }
            else
            {
                userIdentity.AddClaim(new Claim(Helpers.Constantes.EmpresaTrabajoId, "-1"));
                userIdentity.AddClaim(new Claim(Helpers.Constantes.EmpresaTrabajoNombre, string.Empty));
            }

            string userId = userIdentity.GetUserId();
            foreach (var claim in userIdentity.Claims)
            {
                    this.Claims.Add(new IdentityUserClaim()
                    {
                        ClaimType = claim.Type,
                        ClaimValue = claim.Value,
                        UserId = userId
                    });
            }

            return userIdentity;
        }
    }

when debugging, I can see these claims:

identity.Claims.ToList()
Count = 13
    [0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 2}
    [1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: jperez}
    [2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity}
    [3]: {AspNet.Identity.SecurityStamp: b98020c4-f1d6-42d6-9275-ff7975bc75dd}
    [4]: {http://schemas.microsoft.com/ws/2008/06/identity/claims/role: 1}
    [5]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Example Name
    [6]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: jperez@example.com}
    [7]: {Roles: Administrador}
    [8]: {ClienteTrabajoNombre: }
    [9]: {ClienteTrabajoId: -1}
    [10]: {ClienteAsignadoId: -1}
    [11]: {EmpresaTrabajoId: -1}
    [12]: {EmpresaTrabajoNombre: }

Claims from 8 to 12 are my custom ones.

And later I update the custom claims this way:

    public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value)
    {
        if (currentPrincipal != null)
        {
            if (!(currentPrincipal.Identity is ClaimsIdentity identity))
                return;

            // check for existing claim and remove it
            var existingClaim = identity.FindFirst(key);
            if (existingClaim != null)
                identity.RemoveClaim(existingClaim);

            // add new claim
            identity.AddClaim(new Claim(key, value));
            var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
            authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(identity, new AuthenticationProperties() { IsPersistent = true });
        }
    }

The fact is that, after 15 minutes, the custom claims get lost. Only predefined claims are kept.

When debugging, this appears in immediate window:

identity.Claims.ToList()
Count = 13
    [0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 2}
    [1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: jstuardo}
    [2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity}
    [3]: {AspNet.Identity.SecurityStamp: b98020c4-f1d6-42d6-9275-ff7975bc75dd}
    [4]: {http://schemas.microsoft.com/ws/2008/06/identity/claims/role: 1}
    [5]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Jaime Stuardo}
    [6]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: ******@desytec.com}
    [7]: {Roles: Administrador}
    [8]: {ClienteTrabajoNombre: }
    [9]: {ClienteTrabajoId: -1}
    [10]: {ClienteAsignadoId: -1}
    [11]: {EmpresaTrabajoId: -1}
    [12]: {EmpresaTrabajoNombre: }

As you see, my custom claims get back to the values I set when user just logged in GenerateUserIdentityAsync method.

How is the correct way to set my custom claims and to persist in the authentication cookie?

Thanks
Jaime

Developer technologies | ASP.NET | Other
{count} votes

1 answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 78,236 Reputation points Volunteer Moderator
    2022-06-05T22:37:07.413+00:00

    While you have updated the authentication cookie timeout, the openid token inside still expires every 15 minutes. So a new openid token is required. You will then need to re-add the custom role values.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.