Home > Software design >  Create a custom cookie that can be consumed by a NET Core API
Create a custom cookie that can be consumed by a NET Core API

Time:12-09

I have a .NET Core 3.1 API for the backend and an Angular frontend. The auth between the two is fine, done using JWT token. Now, because I need to integrate with another app, I'm adding cookie authentication to the API using this instruction blog. Something like this in Startup.cs:

services.AddAuthentication()
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, opt =>
    {
        opt.Cookie.Name = ".SharedCookie";
        opt.Cookie.Path = "/";
        opt.Cookie.Domain = ".localhost";
        opt.SlidingExpiration = true;
        opt.ExpireTimeSpan = new TimeSpan(24 * 7, 0, 0);
    })

So far so good. The API has an endpoint to register, log in, and sign out. However, I want my API to use the cookie to authorize only. The cookie will be created by another app, not the API or my frontend app.

It means that I have another application (in a different tech stack, e.g., Python, NodeJS) that will take care of the authentication. When the user successfully signs in there, a cookie will supposedly be created and stored in the browser. Then, when the user visits my Angular app and from there, makes requests to my .NET Core API (with the cookie attached), my API can authenticate and authorize based on that cookie.

I have looked around and am not sure what to do on the NET Core side.
For example, from this tutorial, I see that an app can create a cookie like this

res.cookie(
    'token',
    jwt.sign(
        { username: row.username, email: row.email },
        config.secret
    ),
    {
        domain: `.my-domain.com`
    }
);

How can my NET Core API consume this? I'm asking so because it seems the cookie created by NET API is in a different format. I can either change the NET API or change the cookie format created by 3rd-party apps.

Many thanks in advance.

CodePudding user response:

As requirement are completely out of any standard. Our best chance might be building our own Authentication scheme. Something like

public class CustomCookieAuthenticationOptions : AuthenticationSchemeOptions
{
}

public class CustomCookieAuthenticationHandler : AuthenticationHandler<CustomCookieAuthenticationOptions>
{
    public CustomCookieAuthenticationHandler(IOptionsMonitor<CustomCookieAuthenticationOptions> options, ILoggerFactory logger,
        UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
    {
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (Request.Cookies.TryGetValue("myCookie", out var customCookie))
        {
            // Some process to extract data was needed from the cookie and build ticket like below
            var cookieClaims = new[]
            {
                new Claim(ClaimTypes.NameIdentifier, "PreviousProcessValueOne"),
                new Claim(ClaimTypes.Email, "PreviousProcessValueTwo"),
                new Claim(ClaimTypes.Name, "PreviousProcessValueThree")
            };

            var cookieClaimsIdentity = new ClaimsIdentity(cookieClaims, nameof(CustomCookieAuthenticationHandler));
            var customTicket = new AuthenticationTicket(new ClaimsPrincipal(cookieClaimsIdentity), Scheme.Name);
            return Task.FromResult(AuthenticateResult.Success(customTicket));
        }
        
        return Task.FromResult(AuthenticateResult.Fail("Cookie not presented!"));
    }
}

Then register it with authentication process

services.AddAuthentication(opts => opts.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer()
    .AddScheme<CustomCookieAuthenticationOptions, CustomCookieAuthenticationHandler>("MyCustomCookieScheme", null);

When using it to guard our endpoints like

[Authorize(AuthenticationSchemes = "MyCustomCookieScheme")]
public IActionResult TestAuthentication()
{
    return Ok("Authenticated!");
}
  • Related