Gotcha: OPTIONS preflight call getting 401 Unauthorized

This one is a quite stupid problem but as it took me 2 hours to figure it out I’ve decided to write it down.

The problem was related to the fact that on a given controller I had a method

public async Task<LookupData> GetAsync()

which I expected based on my WebAPI v1 days to be HttpGet ONLY by convention.

What I have learned is that is not the case in AspNetCore so this method was triggered also by CORS preflight OPTIONS call and that caused all kind of troubles.

Solution to my problem ended very simple – add a [HttpGet] attribute

[HttpGet]
public async Task<LookupData> GetAsync()

I somehow don’t like to use attributes when I don’t really have to but in this case lesson learn – annotate your AspNetCore controller methods! 🙂

How to override AspNetCore LogLevel from aspsettings.json on Azure App Service?

Here is a post about something which is very dumb  yet it cost me a few hours to figure it out – how to override the Logging configuration from appsettings.json file on the Azure App Service settings?

Basically, you might have your AspNetCore app configured like this

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Error" 
    }
  }
}

It is very simple config – do not show any logs for anything which is less than error (for AspNetCore logs) and nothing below the Information for the rest of the code logging traces.

The problem is that you may have in your code things like this

this.logger.LogDebug("[Group]:message" + JsonConvert.SerializeObject(creationEvent, Formatting.Indented));

You want to take a quick look but without redeploying the app – how to do that?

After 2 hours of searching, it turns out to be quite simple rule for overriding ANY setting.

Replace every { in the appsettings.json file with : in azure app settings

So just add a new Azure App Service setting  with key Logging:LogLevel:Default  and set it to Debug value and once done remove it.

How to add LinkedIn login to your Asp.Net Core app?

If you are of human origin, then most likely you hate remembering all the passwords different websites are forcing you to remember.

(Yes, I use LastPass but still, it is a major PITA)

That is why we have OAuth providers which allow us to login using Facebook, Microsoft, Google and plenty of other social providers which we use anyhow.

As I said previously, on this blog post I treat all of my readers with respect so I will save you 20 minutes of your life by repeating to you basic stuff like what OAuth is and how you can add to your Asp.Net Core app Facebook login.
(In case you would need that: here it is)

Here I will speak about a problem I hit recently: the list of build in providers is limited and we can’t really use the popular .NET 4.6.2 NuGet packages so the question emerged…

If you are busy and just want to have AddLinkedIn() in your code and don’t care about how it works you can either get the source code from my GitHub repo or add a Nivatech.Framework.OAuthProviders Nuget package to your project.

If you want to learn how to make your own OAuth provider for Asp.Net Core just keep reading…

How to add LinkedIn OAuth provider to Asp.Net Core app?

Like many of the things in asp.net core  – making your own LinkedIn (or any other) OAuth provider it turns to be a quite an easy task done in 3 simple steps.

First of all, you need to find some data about OAuth endpoints the provider you want to use exposes. This is always an easy task which takes 10 minutes of Binging with Google as each one of the providers has that publicly documented.

In case of LinkedIn, this is documented on their OAuth documentation page so we will take from their 3 endpoint URLs we need and make out of it LinkedInDefaults class

public static class LinkedInDefaults
{
    public static readonly string DisplayName = "LinkedIn";
    public static readonly string AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
    public static readonly string TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
    public static readonly string UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)";
    public const string AuthenticationScheme = "LinkedIn";
}

The second step is to define OAuthOptions file for LinkedIn provider like this

public class LinkedInOptions : OAuthOptions
{
    public LinkedInOptions()
    {
        this.CallbackPath = new PathString("/signin-linkedin");
        this.AuthorizationEndpoint = LinkedInDefaults.AuthorizationEndpoint;
        this.TokenEndpoint = LinkedInDefaults.TokenEndpoint;

        this.UserInformationEndpoint = LinkedInDefaults.UserInformationEndpoint;
        this.Scope.Add("r_basicprofile");
        this.Scope.Add("r_emailaddress");

        this.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id", ClaimValueTypes.String);
        this.ClaimActions.MapJsonKey(ClaimTypes.Name, "formattedName", ClaimValueTypes.String);
        this.ClaimActions.MapJsonKey(ClaimTypes.Email, "emailAddress", ClaimValueTypes.Email);
        this.ClaimActions.MapJsonKey("picture", "pictureUrl", ClaimValueTypes.String);
    }
}

A few points about this code sample:

  • The callback path is in every provider defined as /signin-SCHEMA_NAME
  • I am defining explicitly the scopes which you can decide to skip and just rely on the company settings defined in the LinkedIn portal
  • The last few lines of code are defining mappings between properties LinkedIn provider is using and the claims you want to store them under.

How can you possibly know what properties certain OAuth provider uses?

Good question – let me show it in the LinkedInHandler file – a 3rd piece of our LinkedIn asp.net core OAuth provider

public class LinkedinHandler : OAuthHandler<LinkedInOptions>
{
    protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
    {
        // Retrieve user info
        var request = new HttpRequestMessage(HttpMethod.Get, this.Options.UserInformationEndpoint);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
        request.Headers.Add("x-li-format", "json");

        var response = await this.Backchannel.SendAsync(request, this.Context.RequestAborted);
        response.EnsureSuccessStatusCode();

        var content = await response.Content.ReadAsStringAsync();
        var user = JObject.Parse(content);

        OAuthCreatingTicketContext context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, this.Context, this.Scheme, this.Options, this.Backchannel, tokens, user);
        context.RunClaimActions();
        await this.Events.CreatingTicket(context);
        return new AuthenticationTicket(context.Principal, context.Properties, this.Scheme.Name);
    }
}

Do you see the line where we parse content into user object? That is the place to put your breakpoint and check what keys json content contains and then you can map them in options as mentioned previously.

So everything is in place and all we need is to create nice extension method where we map options, handler and authorization schema/provider name

public static class OAuthExtension
{
    public static AuthenticationBuilder AddLinkedin(this AuthenticationBuilder builder, Action<LinkedInOptions> linkedinOptions)
    {
        return builder.AddOAuth<LinkedInOptions, LinkedinHandler>("LinkedIn", linkedinOptions);
    }
}

And that’s it – from this moment you can use the LinkedIn provider as any other built-in OAuth provider

services.AddAuthentication()
    .AddLinkedin(options =>
    {
        options.ClientId = this.Configuration.GetValue<string>("LIN_CLIENT");
        options.ClientSecret = this.Configuration.GetValue<string>("LIN_SECRET");
    });

Adding support for other OAuth provider is pretty much the same set of steps (I needed support for GitHub provider so I added it to my GitHub repo) so you should be able to create your own with an ease after reading this article.

Off course if you want to add your providers to the repo so more people can benefit out of it you are more then welcome

How to run Azure app service with Asp.Net Core 2.2 Preview?

So, you like Asp.Net Core 2.2 Preview as much as I do and you want to deploy your website to Azure as app service – easy peasy, right?

Not so fast cowboy! 🙂

Asp.Net Core 2.2 is ATM still in Preview and in order to be able to deploy it to Azure service you need to add 2.2 runtime extension.

First, open your app service and find Extensions section and click add

Then you find Asp.Net  Core 2.2 Runtime extension select it and accept EULA

After a few seconds, the extension is installed and your 2.2 websites are working fine now deployed on Azure.

So go and get that cup of coffee you deserve for a job well done!

How to protect API with JWT tokens in Asp.Net Core

Unless you are a time traveler and just landed in 2018, the app you are working on is using for sure some REST API (we’ll skip GraphQL for now) to CRUD the data it works with.

My preferred technology for implementing such an API is  Asp.Net Core WebAPI so creating endpoints is quite a trivial task.

Protecting the endpoints from the unauthorized access is, unfortunately, a bit less trivial task but still easy in Asp.Net Core compared to how it was done in the past.

In Papiri we are using claims-based authentication using the JWT bearer tokens.

What is JWT?

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties. It is a de facto standard on the web for performing authorization which is not dependent on any technology or platform. If you check out the https://jwt.io/ you can see libraries in many different languages.

Basically JWT token is a base64 encoded string which consists of 3 parts separated by dots – like this one

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o.

You can take this string and paste it on jwt.io to see what it contains…

The first part of that string is called header and it contains things like what algorithm and token type are used.

The second part of the string contains set of claims which we want to be sent as a part of the JWT token. Purpose of this part is to define claims which we want to be part of principal claims once the authorization is complete on API side.

The third part is a signature part which is an encrypted checksum of the previous two sections. Purpose of this part is to verify that the claims sent to the backend have not been tampered and thus making token invalid.

How to create JWT token?

First of all, you need app secret key which you will use to encrypt JWT signature. You DO NOT put that in your git repo, config files etc as if someone will get a hold of it he would be able to generate JWT token with any set of claims impersonating different roles etc.

(You should store app secret it in Azure Key Vault but how to do that is part of some of the future blog posts)

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

Once we transform the secret into the credentials object we need to define the set of claims which will be sent in jwt token – here are claims we use in Papiri app

var claims = new List<Claim>()
{
    new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
    new Claim(JwtRegisteredClaimNames.UniqueName, user.Email),
    new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName),
    new Claim(JwtRegisteredClaimNames.FamilyName, user.FamilyName),
    new Claim(JwtRegisteredClaimNames.Jti, KeyGenerator.GetSecureGuid().ToString()),
    new Claim(JwtRegisteredClaimNames.Iss, issuer),
    new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToEpochMillis().ToString(), ClaimValueTypes.DateTime),
    new Claim(JwtRegisteredClaimNames.Email, user.Email)
};

A few thoughts about the claims:

  • You always need to have jti claim set to some random value on every token generation as a form of salting the signature which makes it harder for cracking
  • iat claim is the claim which represents when the claim is issued at and you can then set the expiration policy which will invalidate claim after x seconds for example which reduces the risk of someone stealing the token and using it in issuing its own calls.
  • As you can tell we send also a few data describing the user in more details which we need to simplify our microservice architecture and avoid cross service authorization calls.

All right, credentials and claims are ready so lets define the token expiration and create it!

var expires = DateTime.Now.AddMinutes(1);

var jwtSecurityToken = new JwtSecurityToken(
    expires: expires,
    claims:claims,
    signingCredentials: creds);

string token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

And there we are – we got the signed JWT token containing our claims.

How to send JWT token with API requests?

The best approach is to send it in Authentication request header in a form of Barer token – something like this

Authentication: Bearer JWT_TOKEN_GOES_HERE

In C# this is usually done like this

using (var client = new HttpClient())
{
     client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
     ...
}

How to authorize API calls with JWT bearer authentication header?

So now there is a call hitting your endpoint with the bearer token, how to use that in your endpoint? In Asp.Net Core that is super easy!

In your Asp.Net Core Startup.cs class find the ConfigureServices method and add this code there

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(cfg =>
    {
        cfg.TokenValidationParameters = new TokenValidationParameters()
        {         
            ValidateAudience = false,
            ValidateIssuer = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = issuer,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(APP_SECRET_HERE))
        };
    });

One more time: do not put app secret in your code – this is just demoware sample – wait until I describe how to store it properly in Azure Key Vault in next blog post 🙂

One more line needed to be added to Configure method

app.UseAuthentication();

Now when we have this set all we need to do is to put the [Authorize] attribute on controller we want to protect and that’s it!

If the token is valid the claims will be transferred to the set of claims User property controller has inside the action and you are good to go!

There you go – crash course in JWT tokens in Asp.Net Core!

Real-user monitoring for Accessibility, Performance, Security, SEO & Errors (SiteLint)