How to Add Authentication and Authorisation to C# REST APIs

Learn how to implement authentication and authorisation in your C# REST APIs, ensure the security of your APIs and protect your data.

By Tim TrottC# ASP.Net MVC • February 5, 2024
1,738 words, estimated reading time 6 minutes.
Writing C# REST APIs

This article is part of a series of articles. Please use the links below to navigate between the articles.

  1. A Beginner's Guide to Building a REST API in C#
  2. Using Swagger to Document and Test Your C# REST API
  3. How to Add Authentication and Authorisation to C# REST APIs
  4. Error Handling and Exception Management in C# REST APIs
  5. Data Validation and Error Handling in REST APIs using C#
  6. Versioning Your C# REST API: Best Practices and Approaches
  7. Caching Strategies for Improved Efficiency in C# REST APIs
  8. How to Implement Rate Limiting in Your C# REST API
How to Add Authentication and Authorisation to C# REST APIs

Authentication and authorisation are essential to developing secure and dependable C # REST APIs. By adopting these features, you can safeguard your data from unauthorised access and ensure that only authorised users have access to your APIs. This article will look at different approaches and techniques for implementing authentication and authorisation in C# REST APIs, giving you the knowledge and tools you need to improve the security of your apps.

Understand the Basics of Authentication and Authorisation

Before going into the implementation details, let's cover the basics of authentication and authorization and how they differ.

Authentication refers to the process of identifying a user or system and confirming its identity against a stored value with the intention of ascertaining that a user is indeed who they claim to be. This is usually done by checking credentials, a username and password combination.

Authorization is the method of deciding whether someone should have access to a certain resource or capability based on the permissions determined at the time of authentication. It denotes what one can do within the system.

REST APIs usually use tokens or API keys for authentication. These tokens are returned on a successful sign-in of a user and then passed on every subsequent API call to confirm his identity. As for authorization, it's usually done with roles and permissions. A role is assigned to every user; different access levels can be granted based on the role.

Laptop with biometric authentication icon graphic
How to Add Authentication and Authorization to C# REST APIs

Choose the Right Authentication Mechanism

When implementing authentication in your C# REST APIs, choosing the appropriate authentication method that meets your specific requirements is important. Various solutions are available, each with its benefits and drawbacks.

Token-based authentication is a common authentication approach in which a token is generated and supplied to the user upon successful authentication. This token is then used to authenticate the user in subsequent API queries. Token-based authentication is commonly used because it provides a secure approach to authenticate users without storing sensitive information such as passwords.

API keys, unique IDs issued to each user or application, are another alternative. API keys are often included in request headers or query parameters to authenticate the user. This approach is easier to set up but may give a different level of security than token-based authentication.

You could also connect with external authentication providers like OAuth or OpenID Connect. These protocols enable users to authenticate using their existing credentials from prominent platforms such as Google, Facebook, and Microsoft. This can ease user authentication while also adding a degree of protection.

The authentication method is determined by criteria such as the level of security required, the complexity of implementation, and the user experience. It is important to thoroughly consider your options and select the one that best meets your requirements.

Implement User Registration and Login Functionality

User registration and login functionalities are essential for authentication and authorization across your C# REST APIs. Users can sign up themselves, securely store their credentials, and then authenticate whenever they access any protected site.

To implement user registration, create a registration endpoint that gets user details such as a username, email address, and password. It would then have to validate user data input, check for any duplicate username or email, and securely hash the password using some salting and hashing algorithm.

Once a user is registered, you will implement the logging-in functionality. Primarily, this means the implementation of a login endpoint that would receive credentials from the user - username/ email and password- and compare that to the stored information. If valid, you could issue a token or session identifier that would then be used to authenticate the user for further requests.

Handling authentication failures with grace and providing relevant error messages is essential. For instance, a response indicating an unsuccessful login should be provided if a user enters an incorrect password. This approach enhances the user experience and maintains the security of your C # REST APIs.

Consider implementing features like password reset, email verification, and multi-factor authentication to enhance the security of your application.

Implement Role-Based Authorization

Role-based authorisation is key to integrating authentication and authorisation in your C# REST APIs. It gives you the power to control access to different areas of your API based on the users' roles, enhancing the security and control of your application.

To begin implementing role-based permission, you must first define the roles in your system. These roles can be assigned to users based on their job title, department, or any other criterion that makes sense for your application.

Once the roles have been defined, they can be assigned to users during registration or via an administration interface. Each user can be allocated one or more roles.

You can then use role-based authorisation characteristics in your API to restrict access to specific endpoints or activities based on the roles necessary. For example, you can use the [Authorize(Roles="Admin")] attribute to restrict access to a specific endpoint to users with the "Admin" role.

Role-based authorisation can also be used with other authorisation strategies, such as claims or resource-based authorisation, to enable finer-grained access control.

Example Of Securing C# REST API Using JSON Web Tokens (JWT)

Adding authentication to an ASP.NET Core Web API can be accomplished in various ways. Still, one popular option is to use JSON Web Tokens (JWT). In this example, I'll teach you how to add JWT-based authentication to your API.

Install Required Packages

For JWT-based authentication, you must install the necessary NuGet packages. Open a terminal in the root directory of your project and run the following commands.

powershell
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt

Configure JWT Authentication

Add and configure JWT authentication in the ConfigureServices and Configure methods of the Startup.cs.file.

C#
using Microsoft.AspNetCore.Authentication.JwtBearer;
   using Microsoft.IdentityModel.Tokens;

   public void ConfigureServices(IServiceCollection services)
   {
       // ... other configurations ...

       // Configure JWT authentication
       var key = Encoding.ASCII.GetBytes("your-secret-key"); // Change this to a strong, secret key
       services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
           .AddJwtBearer(options =>
           {
               options.RequireHttpsMetadata = false;
               options.SaveToken = true;
               options.TokenValidationParameters = new TokenValidationParameters
               {
                   ValidateIssuerSigningKey = true,
                   IssuerSigningKey = new SymmetricSecurityKey(key),
                   ValidateIssuer = false,
                   ValidateAudience = false
               };
           });
   }

   public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
   {
       // ... other configurations ...

       app.UseAuthentication();
       app.UseAuthorization();
   }

Ensure that your-secret-key is replaced with a robust and secret key. This key should be kept secure in a production setting.

Authentication Attributes

You can use authentication attributes in your controller to protect specific endpoints. For example, suppose you want to require authentication for all methods in your TemperatureController. In that case, you can use the [Authorise] attribute.

C#
[Authorize]
[Route("api/temperature")]
[ApiController]
public class TemperatureController : ControllerBase
{
    // ... controller actions ...
}

Generating JWT Tokens

To issue JWT tokens to authenticated users, you'll need a mechanism. Typically, this entails developing a controller action that receives credentials (e.g., username and password) and returns a JWT token upon successful authentication. The above example assumes that you have such functionality in place. The user's credentials would be validated, and this authentication controller would generate a JWT token. We'll see this mechanism in the next section below.

Calling Authenticated Endpoints

When making API requests, clients must include the JWT token in the HTTP request's 'Authorisation' header. The token should be something like 'Bearer your-token'. In a client application, for example, you might add the token as follows:

GET /api/temperature/celsius-to-fahrenheit?celsius=25
Authorization: Bearer your-token-here

Securing C# REST API's with Username and Password

Many applications require username and password authentication to secure an ASP.NET Core REST API. You can combine ASP.NET Identity and JWT (JSON Web Tokens). Here are the steps to using a username and password to safeguard your ASP.NET Core REST API.

Install Required Packages

Install the necessary packages for working with ASP.NET Identity and JWT.

powershell
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Create a User Model

Create a user model that represents an API user. You can utilise the built-in ASP.NET Identity's IdentityUser class or construct your own. If you wish to construct a custom user class, it should inherit from IdentityUser.

C#
public class ApplicationUser : IdentityUser
{
    // Add custom properties if needed
}

Configure Identity

Configure ASP.NET Identity in the ConfigureServices method of the Startup.cs file.

C#
   services.AddDbContext<ApplicationDbContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

   services.AddIdentity<ApplicationUser, IdentityRole>()
       .AddEntityFrameworkStores<ApplicationDbContext>()
       .AddDefaultTokenProviders();

Make careful to specify DefaultConnection in the appsettings.json file when configuring your database connection.

Configure JWT Authentication

Configure JWT authentication as shown in the previous example in the ConfigureServices method.

User Registration and Login

Create user registration and login controllers and actions. First, create a user account and generate a JWT token upon successful registration. Then, validate user credentials and generate a token to log in.

Here's a simplified example of user registration and login.

C#
[Route("api/account")]
[ApiController]
public class AccountController : ControllerBase
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IConfiguration _configuration;

    public AccountController(UserManager<ApplicationUser> userManager, IConfiguration configuration)
    {
        _userManager = userManager;
        _configuration = configuration;
    }

    [HttpPost("register")]
    public async Task<IActionResult> Register([FromBody] RegistrationModel model)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await _userManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            var token = GenerateJwtToken(user);
            return Ok(new { token });
        }

        return BadRequest(result.Errors);
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginModel model)
    {
        var user = await _userManager.FindByNameAsync(model.Email);

        if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
        {
            var token = GenerateJwtToken(user);
            return Ok(new { token });
        }

        return Unauthorized();
    }

    private string GenerateJwtToken(IdentityUser user)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes("your-secret-key");

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(ClaimTypes.NameIdentifier, user.Id)
                // Add additional claims as needed
            }),
            Expires = DateTime.UtcNow.AddHours(1), // Token expiration time
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
}

Authentication Middleware

Ensure that your API employs authentication middleware. Add the following to the 'Configure' method in Startup.cs.

C#
app.UseAuthentication();
app.UseAuthorization();

Use JWT Token for Authorized Requests

For actions that require authorisation, add the `[Authorize]` attribute to your controller actions.

C#
[Authorize]
[HttpGet("secure-data")]
public IActionResult GetSecureData()
{
    // Your secured endpoint logic here
}

Testing Authentication

Endpoints for user registration and login are now available for testing. To access secured endpoints, include the JWT token in your HTTP requests 'Authorisation' header.

This is a basic example of using username and password authentication to secure an ASP.NET Core REST API. In a production environment, you should use stronger security measures, handle token expiration and refresh, and consider user management and responsibilities. You should keep your private key safe and use HTTPS for secure data transmission.

About the Author

Tim Trott is a senior software engineer with over 20 years of experience in designing, building, and maintaining software systems across a range of industries. Passionate about clean code, scalable architecture, and continuous learning, he specialises in creating robust solutions that solve real-world problems. He is currently based in Edinburgh, where he develops innovative software and collaborates with teams around the globe.

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

My website and its content are free to use without the clutter of adverts, popups, marketing messages or anything else like that. If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

There are no comments yet. Why not get the discussion started?

New comments for this post are currently closed.