Home > database >  How do the ASP.NET Core 5 OpenIdConnect authentication cookies work in theory?
How do the ASP.NET Core 5 OpenIdConnect authentication cookies work in theory?

Time:12-11

We are trying to understand how the authentication cookies (ASP.NET Core 5.0 - Microsoft.AspNetCore.Authentication.OpenIdConnect version 5.0.11) work with the Authorization Code Flow without PKCE.

Auth Process

The auth process looks like this: the login in the frontend redirects to the login endpoint of the AuthController and starts the OpenId Connect process. So you are authenticated by the Identity Provider and the cookies are set for the user. Which are sent with every call of the API to check if the request is authenticated.

3 cookies are created in the process:

Cookie #1:

  • Name = .AspNetCore.Cookies
  • Value = chunks-2

Cookie #2:

  • Name = .AspNetCore.CookiesC1
  • Value = CfDJ8GRK-GHfascFTvp0o_E7oKZU-6GOAbUGCPHZZPfewEv12PmKgr46gfeTQC351e-Jnxq8SxzjJEgboIedIPCO11Q […]

Cookie #3:

  • Name = .AspNetCore.CookiesC2
  • Value = 8G86qN27NOS2Z-75XqY34d-ID1nOELpPaHUIe2EkFZMmfjrYSKA2JaU30p4Ozh8RyxZXTpFCRV8

Questions

  • How are these .AspNetCore cookies used for authentication?
  • How are the names generated and the value encrypted?
  • What does these cookies contain?

We tried to decrypt the cookie (How to manually decrypt an ASP.NET Core Authentication cookie?) to understand how it works but this did not work for us.

Unfortunately, we have not yet found an answer as to how the cookie is generated (with name and value) in theory.

I hope the questions were understandable and I would appreciate if someone could answer them.

Code snippets for a better understanding. Hopefully :)

AuthController:

// https://auth0.com/blog/backend-for-frontend-pattern-with-auth0-and-dotnet/
public class AuthController : Controller
{
    public ActionResult Login(string returnUrl = "/login")
    {
        return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties() { RedirectUri = returnUrl });
    }

    [Authorize]
    public async Task<ActionResult> Logout()
    {
        await HttpContext.SignOutAsync();

        return new SignOutResult(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
        {
            //RedirectUri = Url.Action("Index", "Home")
            RedirectUri = "/logout"
        });
    }

    //[Authorize]
    public ActionResult GetUser()
    {
        var jsonReturn = new Dictionary<string, string>();

        if (User != null && User.Identity.IsAuthenticated)
        {
            jsonReturn.Add("isAuthenticated", "true");

            foreach (var claim in ((ClaimsIdentity)this.User.Identity).Claims)
            {
                jsonReturn.Add(claim.Type, claim.Value);
            }

            return Json(JsonConvert.SerializeObject(jsonReturn));
        }

        jsonReturn.Add("isAuthenticated", "false");
        return Json(JsonConvert.SerializeObject(jsonReturn));
    }
}

Startup:

public void ConfigureServices(IServiceCollection services)
{
     JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

     services.AddAuthentication(options =>
     {
          options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
     })
     .AddCookie(o =>
     {
          o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
          o.Cookie.SameSite = SameSiteMode.Strict;
          o.Cookie.HttpOnly = true;
     })
     .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => ConfigureOpenIdConnect(options));
}

private void ConfigureOpenIdConnect(OpenIdConnectOptions options)
{
        options.Authority = <identity provider url>;
        options.ClientId = "<clientId>";
        options.ClientSecret = "<clientSecret>";

        options.ResponseMode = OpenIdConnectResponseMode.FormPost;
        options.Scope.Clear();
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("offline_access");
        
        options.CallbackPath = new PathString("/callback");
        options.SaveTokens = true;
        options.UseTokenLifetime = false;
}

CodePudding user response:

The .AspNetCore cookie is created by the Cookie authentication handler after the user has successfully authenticated (being challenged) with the OpenIDConnect handler.

If The cookie size is to big, then it will be broken up into chunks of 4Kb to make sure the cookies don't get rejected the browser or proxies.

The data inside the cookies is encrypted using the Data Protection API and with some effort you can decrypt the content of the cookie using the Data Protection aPI.

the data inside the cookie contains mainly of your ClaimsPrincipal (The user objects) with its various claims. Optionally you can also store your openid-connect tokens inside the cookie.

Hope this answers your questions.

  • Related