In my 11 years as a developer, I have seen so many API's that have major security flaws. They either lack proper authentication or authorisation or both. Developers might feel like everything's ok, since those endpoints are usually not public. But it is a huge security loop hole which anyone can easily target. To better understand API security, let's create a demo project for the FBI. There will be an Admin who can enroll FBI Agents and change their clearance levels. FBI Agents with will be able to access public files, and agents with will be able to access pubic and classified files. Clearance Level 1 Clearance Level 2 But before we get started, here's some theory. How Authentication Works Our Agent has successfully cleared all their exams; time to enroll them. In order to do that they will provide their documents and in return will get their badge. In the above scenario, is like logging in – where once verified, the agent will be provided with a token (badge). This process is called . It determines whether agents are who they claim to be. providing documents Authentication We are going to use JSON Web Tokens (JWT) Bearer tokens for authentication. are a type of token that's generated by servers, and which contain details of the claims/roles of a user trying to login. Bearer tokens are mostly structured tokens like JWT. You can if you want to learn more. Bearer tokens read more about JWT here How Authorisation Works Now since the FBI Agent has gotten their badge, they can enter the FBI building. They are also able to access public files, but when trying to access classified files they get a . 401 error This is because FBI Agent is not to access classified files. determines what agents can and cannot access. authorised Authorisation As mentioned above, the JWT Bearer token contains claims/roles. Based on it, our server decides whether to give access to a private resource or not. Access Flow As you can see in the above diagram, on successful login the server returns a Bearer token. The client uses the bearer token in subsequent calls to access a private resource. These are the two main concepts that we are going to implement in our article. Enough with the theory, show me some code! How to Set Up our Project Create a new project by executing the command from your CLI. It will create a project with a sample WeatherForecast API. dotnet new webapi --name FBI Why work on WeatherForecast when we can work on FBI? Go ahead and delete the WeatherForecast.cs file. Add the necessary dependencies by executing these commands: dotnet add package Microsoft.IdentityModel.Tokens --version 6.9.0 dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 5.0.4 In the ConfigureServices function in your Startup.cs file, add the below code: var TokenValidationParameters = TokenValidationParameters { ValidIssuer = , ValidAudience = , IssuerSigningKey = SymmetricSecurityKey(Encoding.UTF8.GetBytes( )), ClockSkew = TimeSpan.Zero // remove token expire }; new "https://fbi-demo.com" "https://fbi-demo.com" new "SXkSqsKyNUyvGbnHs7ke2NCq8zQzNLW7mPmHbnZZ" delay of when We are defining the parameters for validating a token. Make sure that the length of the string for generating SymmetricSecurityKey is 32. Next, setup the services to add authentication for API's like this: services ; .AddAuthentication ( => { options. = JwtBearerDefaults.AuthenticationScheme; }) options DefaultScheme .AddJwtBearer ( => { cfg. = TokenValidationParameters; }) cfg TokenValidationParameters The AddAuthentication method registers services required by authentication services. It also configures the JWT Bearer Authentication as the default scheme. The AddJwtBearer enables JWT-bearer authentication and setting the TokenValidationParameters defined above. Now let's add some Authorisation claims for our Agent and Admin. services.AddAuthorization(cfg => { cfg.AddPolicy( , => policy.RequireClaim( , )); cfg.AddPolicy( , => policy.RequireClaim( , )); cfg.AddPolicy( , => policy.RequireClaim( , , )); cfg.AddPolicy( , => policy.RequireClaim( , )); }); "Admin" policy "type" "Admin" "Agent" policy "type" "Agent" "ClearanceLevel1" policy "ClearanceLevel" "1" "2" "ClearanceLevel2" policy "ClearanceLevel" "2" The AddAuthorization method registers services required for authorisation. We are also adding claims for Admin, Agent, ClearanceLevel1 and ClearanceLevel2 by calling AddPolicy. A claim is a name value pair that represents what the subject is. Since clearance level 2 can also access clearance level 1, we have put in ClearanceLevel1. You can read more about claims . "1", "2" here Lastly, in the Configure method, add the below line just above app.UseAuthorization(); app.UseAuthentication() ; The Admin Controller File Rename your file WeatherForecastController.cs to AdminController.cs. Do change the class name and constructor names as well. Finally, remove everything except the constructor. Microsoft.AspNetCore.Mvc; { [ ] [ ] : { { } } } using namespace FBI.Controllers ApiController Route( ) "[controller]" public class AdminController ControllerBase ( ) public AdminController Let's create a login API for Admin so that they can get a token to perform other tasks. [ ] [ ] { Claims = List<Claim> { Claim( , ), }; Key = SymmetricSecurityKey(Encoding.UTF8.GetBytes( )); Token = JwtSecurityToken( , , Claims, expires: DateTime.Now.AddDays( ), signingCredentials: SigningCredentials(Key, SecurityAlgorithms.HmacSha256) ); OkObjectResult( JwtSecurityTokenHandler().WriteToken(Token)); } HttpPost Route( ) "[action]" IActionResult ( ) public Login [FromBody] User User // Authenticate Admin with Database TODO: // If not authenticate return 401 Unauthorized // Else continue with below flow var new new "type" "Admin" var new "SXkSqsKyNUyvGbnHs7ke2NCq8zQzNLW7mPmHbnZZ" var new "https://fbi-demo.com" "https://fbi-demo.com" 30.0 new return new new In the above code, User is a model with properties Username and Password. We are also creating an object of JwtSecurityToken using configurations that we have used in our Startup.cs file. The token is then converted to a string and returned in an OkObjectResult. You can now open Swagger and execute the API to see a bearer token. A bearer token will be returned as you can see below. Keep the token handy since we are going to use it in the next section. You can also visit to analyse your token. https://jwt.io How to Generate the Badge API Generating the badge for an Agent is a sensitive task and should only be authorised by an Admin. We are going to add an Authorize attribute for the GenerateBadge API. [ ] [ ] [ ] { CreatedResult( , Agent); } HttpPost Route( ) "[action]" Authorize(Policy = ) "Admin" IActionResult ( ) public GenerateBadge [FromBody] Agent Agent // Add the agent to the database TODO: return new "Agent/1" Here, Agent is a model with properties Name as string and ClearanceLevel as int. Now when you go back to swagger and try to execute the GenerateBadge API it will give you a 401 Unauthorised response. We are getting this error because we have not passed the bearer token. To be able to add the Authorize header in Swagger, change the services.AddSwaggerGen as below: services.AddSwaggerGen(c => { c.SwaggerDoc( , new OpenApiInfo { Title = , Version = }); c.AddSecurityDefinition( , new OpenApiSecurityScheme { = ParameterLocation.Header, Description = , Name = , = SecuritySchemeType.ApiKey }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { = ReferenceType.SecurityScheme, Id = } }, new string[] {} } }); }); "v1" "FBI" "v1" "Bearer" In "Please enter JWT with Bearer into field" "Authorization" Type Type "Bearer" When you refresh Swagger in your browser you will notice an button on the right side above the list of APIs. Authorize Click on the newly added Authorize button in Swagger which will open up a dialog. We need to mention what type of token it is. So first enter in the field then a space and then the token generated from the API from the previous section. Bearer /Admin/Login Click on the header to lock in the token. Now you are all set. When you execute the GenerateBadge API again you will get a token (analogous to badge). Keep this token handy, since we require it in the next section. Also make sure to for now. pass ClearanceLevel as 1 How to Set Up the Agent Controller Create a new file called AgentController.cs with the below content: Microsoft.AspNetCore.Mvc; { [ ] [ ] [ ] : { { } } } using namespace FBI.Controllers ApiController Route( ) "[controller]" Authorize(Policy = ) "Agent" public class AgentController ControllerBase ( ) public AgentController As you can see above, we are authorising the whole controller for Agent's access only. So even Admin won't be able to access the API's we are going to create. How to Access the Record's APIs Let's add the APIs to access both public and classified files. [ ] [ ] [ ] { OkObjectResult( ); } [ ] [ ] [ ] { OkObjectResult( ); } HttpGet Route( ) "[action]" Authorize(Policy = ) "ClearanceLevel1" ActionResult<String> ( ) public AccessPublicFiles return new "Public Files Accessed" HttpGet Route( ) "[action]" Authorize(Policy = ) "ClearanceLevel2" ActionResult<String> ( ) public AccessClassifiedFiles return new "Classified Files Accessed" We have added the Authorize attribute's for both API's such that public files can be accessed by ClearanceLevel1 and classified files can be accessed by ClearanceLevel2. If you try to access these API's with the Admin token you will get 403 Forbidden error. So go ahead and click on the button again and click on . Then, get the token from the above step and paste in the field with as a prefix Authorize logout Bearer . Now when you access the API you will see response 200 with the message . But when you try the classified API you get the 403 Forbidden error. /Agent/AccessPublicFiles Public Files Accessed How to Change the Clearance Level Fast forward 3 years and our performance has been mind bogglingly good. Management has now decided to promote them to ClearanceLevel2. Agent's The goes to the and asks them to provide a token/badge with Clearance Level 2. Agent Admin The calls the API to generate their own token first. They then enter it in the dialog. Admin /Admin/Login Authorize The admin then calls the API with value 2 in the ClearanceLevel. This generates a new token/badge which they then hand over to . /Admin/GenerageBadge Agent The enters this token/badge in the dialog and when they now call they are pleased to see the result . Agent Authorize /Agent/AccessClassifiedFiles Classified Files Accessed Conclusion You can find the whole project on GitHub. here API security is extremely important and shouldn't be taken lightly, even if it's for internal use only. Setup Authentication and Authorisation and you are halfway there. There are other other security measures you can take against DDoS attacks, accepting API's from a particular IP or domain only, and so on. How did you like the article? What other security measures do you usually take? Any feedbacks or comments? You can checkout out more tutorials . here Previously published at https://arjavdave.com/2021/03/31/net-5-setup-authentication-and-authorisation/