title: ASP.Net Core 2.1 IdentityCore (Role Claims not being added on user sign in)
body: <p>I'm using <strong>ASP.Net Core 2.1</strong> with <strong>IdentityCore Service</strong>, the application is a pure API, no views at all. For authentication I'm purely using <strong>Steam authentication</strong> (No User/Pass login) provided by, <a href="https://github.com/aspnet-contrib/AspNet.Security.OpenId.Providers" rel="nofollow noreferrer">https://github.com/aspnet-contrib/AspNet.Security.OpenId.Providers</a></p>
  
  <p>This API has been created to fit a very specific authentication workflow (User's can only login to the API with Steam) the Angular SPA sitting as the frontend handles the workflow just fine.</p>
  
  <p><strong>The problem</strong> is that when I add a Role to a user (I've already got roles seeded and I've added my own steam account to the Admin Role), the role type claims are not being added on login, therefore when an admin user attempts to access an API route protected by [Authorize(Roles = "Admin") I'm being returned an Unauthorized Redirect.</p>
  
  <p>Below I have added all code snippets I think is required (feel free to request more).</p>
  
  <p>If I use (I am currently using this as a temporary solution, but it is not ideal for future development);</p>
  
  <pre><code>services.AddIdentity&lt;User, Role&gt;()
     .AddEntityFrameworkStores&lt;RSContext&gt;()
     .AddSignInManager&lt;SignInManager&lt;User&gt;&gt;()
     .AddRoleManager&lt;RoleManager&lt;Role&gt;&gt;()
     .AddDefaultTokenProviders();
  </code></pre>
  
  <p>The application correctly adds the role claims on user sign in (and the Authorize attributes work), using all existing code from AuthController.cs, yet using IdentityCore it fails. I feel I am missing a single line that is responsible for this but after trolling MSDN docs for days I am finally outwitted.</p>
  
  <p><strong>NOTE:</strong> The API will <strong>correctly authenticate</strong> and set the users cookies on sign in, but does not add the users roles to the users identity claims. Therefore, Authentication is Working, Authorization is not. If I utilise the [Authorize] attribute without specifying a Role it works flawlessly and only allows Authenticated users to access the route whilst denying unAuthenticated users. This can be seen in the Testing Screenshot at the end, identities[0].isAuthenticated = True, but the admin role is not being added to the Identity's Claims. As noted above, if I do not use AddIdentityCore and use AddIdentity, the roles are added to the user's claims correctly and the [Authorize(Role = "Admin")] attribute will work as expected, only allowing users that are apart of the Admin role to access it.</p>
  
  <p>Startup.cs (Omitted irrelevant parts, eg. Database Connection)</p>
  
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      IdentityBuilder builder = services.AddIdentityCore&lt;User&gt;(opt =&gt;
      {
          opt.Password.RequireDigit = true;
          opt.Password.RequiredLength = 6;
          opt.Password.RequireNonAlphanumeric = true;
          opt.Password.RequireUppercase = true;
          opt.User.AllowedUserNameCharacters += ":/";
      });
  
      builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services);
      builder.AddEntityFrameworkStores&lt;RSContext&gt;();
      builder.AddSignInManager&lt;SignInManager&lt;User&gt;&gt;();
      builder.AddRoleValidator&lt;RoleValidator&lt;Role&gt;&gt;();
      builder.AddRoles&lt;Role&gt;();
      builder.AddRoleManager&lt;RoleManager&lt;Role&gt;&gt;();
      builder.AddClaimsPrincipalFactory&lt;UserClaimsPrincipalFactory&lt;User&gt;&gt;();
      builder.AddDefaultTokenProviders();
  
      services.AddAuthentication(options =&gt;
      {
          options.DefaultScheme = IdentityConstants.ApplicationScheme;
          options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
          options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
          options.DefaultSignInScheme = IdentityConstants.ApplicationScheme;
          options.DefaultSignOutScheme = IdentityConstants.ApplicationScheme;
          options.DefaultForbidScheme = IdentityConstants.ApplicationScheme;
      })
          .AddSteam(options =&gt;
          {
              options.ApplicationKey = Configuration.GetSection("Authentication:Steam:Key").Value;
              options.CallbackPath = "/api/auth/steam/callback";
              options.Events.OnAuthenticated = OnClientAuthenticated;
          })
          .AddIdentityCookies(options =&gt;
          {
              options.ApplicationCookie.Configure(appCookie =&gt;
              {
                  appCookie.Cookie.Name = "RaidSimulator";
                  appCookie.LoginPath = "/api/auth/login";
                  appCookie.LogoutPath = "/api/auth/logout";
                  appCookie.Cookie.HttpOnly = true;
                  appCookie.Cookie.SameSite = SameSiteMode.Lax;
                  appCookie.Cookie.IsEssential = true;
                  appCookie.SlidingExpiration = true;
                  appCookie.Cookie.Expiration = TimeSpan.FromMinutes(1);
                  appCookie.Cookie.MaxAge = TimeSpan.FromDays(7);
              });
              options.ExternalCookie.Configure(extCookie =&gt;
              {
                  extCookie.Cookie.Name = "ExternalLogin";
                  extCookie.LoginPath = "/api/auth/login";
                  extCookie.LogoutPath = "/api/auth/logout";
                  extCookie.Cookie.HttpOnly = true;
                  extCookie.Cookie.SameSite = SameSiteMode.Lax;
                  extCookie.Cookie.IsEssential = true;
                  extCookie.Cookie.Expiration = TimeSpan.FromMinutes(10);
              });
          });
  }
  
  public void Configure(IApplicationBuilder app, IHostingEnvironment env, RoleManager&lt;Role&gt; roleManager)
  {
      if (env.IsDevelopment())
      {
          app.UseDeveloperExceptionPage();
      }
  
      RolesSeed.Seed(roleManager).Wait();
  
      app.UseCors();
      app.UseAuthentication();
      app.UseMvc();
  }
  
  // Responsible for storing/updating steam profile in database
  private async Task OnClientAuthenticated(OpenIdAuthenticatedContext context)
  {
      var rsContext = context.HttpContext.RequestServices.GetRequiredService&lt;RSContext&gt;();
      var userManager = context.HttpContext.RequestServices.GetRequiredService&lt;UserManager&lt;User&gt;&gt;();
  
      var profile = context.User?.Value&lt;JObject&gt;(SteamAuthenticationConstants.Parameters.Response)
                          ?.Value&lt;JArray&gt;(SteamAuthenticationConstants.Parameters.Players)?[0]?.ToObject&lt;SteamProfile&gt;();
  
      // TODO: Handle this better, Redir user to an informative error page or something
      if (profile == null)
          return;
  
      var dbProfile = await rsContext.SteamProfiles.FindAsync(profile.SteamId);
      if (dbProfile != null)
      {
          rsContext.Update(dbProfile);
          dbProfile.UpdateProfile(profile);
          await rsContext.SaveChangesAsync();
      }
      else
      {
          await rsContext.SteamProfiles.AddAsync(profile);
          await rsContext.SaveChangesAsync();
      }
  }
  </code></pre>
  
  <p>AuthController.cs => The only code responsible for authenticating against the Identity.Application scheme</p>
  
  <pre><code>[HttpGet("callback")]
  [Authorize(AuthenticationSchemes = "Steam")]
  public async Task&lt;IActionResult&gt; Callback([FromQuery]string ReturnUrl)
  {
      ReturnUrl = ReturnUrl?.Contains("api/") == true ? "/" : ReturnUrl;
  
      if (HttpContext.User.Claims.Count() &gt; 0)
      {
          var provider = HttpContext.User.Identity.AuthenticationType;
          var nameIdentifier = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
          var name = HttpContext.User.FindFirstValue(ClaimTypes.Name);
  
          var loginResult = await signInManager.ExternalLoginSignInAsync(provider, nameIdentifier, false);
          if (loginResult.Succeeded)
          {
              return Redirect(ReturnUrl ?? "/api/auth/claims");
          }
  
          var result = await userManager.CreateAsync(new User { UserName = nameIdentifier, SteamId = nameIdentifier.Split("/").Last() });
          if (result.Succeeded)
          {
              var user = await userManager.FindByNameAsync(nameIdentifier);
              var identity = await userManager.AddLoginAsync(user, new UserLoginInfo(provider, nameIdentifier, name));
  
              if (identity.Succeeded)
              {
                  await signInManager.ExternalLoginSignInAsync(provider, nameIdentifier, false);
                  return Redirect(ReturnUrl ?? "/api/auth/claims");
              }
          }
      }
  
      return BadRequest(new { success = false });
  }
  
  [HttpGet("claims")]
  [Authorize]
  public async Task&lt;IActionResult&gt; GetClaims()
  {
      var user = await userManager.GetUserAsync(User);
      var claims =
          User.Claims.Select(c =&gt; new
          {
              c.Type,
              c.Value
          });
  
      var inAdmin = new string[] {
          "User.IsInRole(\"Admin\") = " + User.IsInRole("Admin"),
          "User.IsInRole(\"ADMIN\") = " + User.IsInRole("ADMIN"),
          "User.IsInRole(\"admin\") = " + User.IsInRole("admin"),
          "userManager.IsInRoleAsync(user, \"admin\") = " + await userManager.IsInRoleAsync(user, "admin")
      };
  
      return Ok(new { success = true, data = new { claims, inAdmin, User.Identities } });
  }
  </code></pre>
  
  <p>RoleSeeder.cs</p>
  
  <pre><code>public static async Task Seed(RoleManager&lt;Role&gt; roleManager)
  {
      // Developer Role
      if(!await roleManager.RoleExistsAsync("Developer"))
      {
          var role = new Role("Developer");
          await roleManager.CreateAsync(role);
      }
      // Community Manager Role
      if (!await roleManager.RoleExistsAsync("Community Manager"))
      {
          var role = new Role("Community Manager");
          await roleManager.CreateAsync(role);
      }
      // Admin Role
      if (!await roleManager.RoleExistsAsync("Admin"))
      {
          var role = new Role("Admin");
          await roleManager.CreateAsync(role);
      }
      // Moderator Role
      if (!await roleManager.RoleExistsAsync("Moderator"))
      {
          var role = new Role("Moderator");
          await roleManager.CreateAsync(role);
      }
  }
  </code></pre>
  
  <p>Testing Screenshot:
  <a href="https://i.stack.imgur.com/oarHT.png" rel="nofollow noreferrer">claims/identities/roletest API Response</a></p>