Resource Server using ASP.NET Core Web API

How to Implement the Resource Server using ASP.NET Core Web API

In this article, I will discuss how to implement the Resource Server Application using ASP.NET Core Web API. Please read our previous article discussing how to implement the Authentication Server Application using ASP.NET Core Web API. This is the Second Application of our SSO Implementation.

Resource Server using ASP.NET Core Web API

A Resource Server is an API that hosts protected data or resources, ensuring that only authenticated and authorized clients can access those resources. In modern web applications, this protection is often enforced using JSON Web Tokens (JWTs), a secure and compact way to transmit authentication information between parties.

Now, we will create a simple ASP.NET Core Web API Resource Server that demonstrates how to secure API endpoints using JWT authentication. Our application will feature two types of endpoints:

  • Public Endpoint: Accessible by anyone without authentication.
  • Protected Endpoint: Requires a valid JWT token for access, ensuring only authorized clients can reach it.

This example will help you understand how to integrate JWT authentication middleware into your ASP.NET Core Web API project to protect your APIs effectively.

Creating a New ASP.NET Core Web API Project

Open Visual Studio and create a new ASP.NET Core Web API project with the name ResourceServer, and then install the following NuGet packages via the Package Manager Console by executing the following command. This package provides the necessary middleware and configuration to validate JWT tokens in your application.

  • Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Configuring JWT Keys in AppSettings.json file:

Open the appsettings.json file to store JWT-related settings, such as the secret key and issuer. These settings are crucial for token validation and securing your API:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Jwt": {
    "Key": "KHPK6Ucf/zjvU4qW8/vkuuGLHeIo0l9ACJiTaAPLKbk=", //Secret Key
    "Issuer": "https://localhost:7035" //Authentication Server Domain URL Base Address
  }
}
Explanation of Key Fields:
  • Key: This is a secret cryptographic key used to sign JWT tokens. It ensures that only tokens signed with this key are accepted by your Resource Server, preventing tampering.
  • Issuer: The identity (URL or name) of the authority that issued the JWT token. When a token is received, the Resource Server verifies that the token’s issuer matches this value to ensure the token is trustworthy.
Configure JWT Authentication in the Resource Server

Next, we need to configure the ASP.NET Core pipeline to use JWT authentication and specify how incoming tokens should be validated. So, please modify the Program.cs file as follows.

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace ResourceServer
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Register controllers and disable the default camel-casing of JSON property names.
            builder.Services.AddControllers().AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNamingPolicy = null;
            });

            // Register JWT Authentication services.
            builder.Services.AddAuthentication(options =>
            {
                // Set the default authentication scheme to JWT Bearer.
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(options =>
            {
                // Configure how the JWT token is validated.
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,               // Set to false if you don't want to Validate Issuer.
                    ValidateAudience = false,            // Set to true if you want to validate the audience.
                    ValidateLifetime = true,             // Ensures the token hasn't expired.
                    ValidateIssuerSigningKey = true,     // Validates that the token is signed with a trusted key.
                    ValidIssuer = builder.Configuration["Jwt:Issuer"],
                    IssuerSigningKey = new SymmetricSecurityKey(
                        Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"] ?? string.Empty))
                };
            });

            // Register Swagger/OpenAPI services for API documentation and testing.
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Enable Swagger UI in development mode.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            // Add the authentication and authorization middleware.
            app.UseAuthentication();
            app.UseAuthorization();

            app.MapControllers();

            app.Run();
        }
    }
}
Creating Demo Controller

Create a new API Empty controller named DemoController.cs under the Controllers folder. This controller will demonstrate the difference between public and protected endpoints.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ResourceServer.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DemoController : ControllerBase
    {
        // GET: /api/demo/public-data
        // This endpoint is open and does not require any authentication.
        [HttpGet("public-data")]
        public IActionResult GetPublicData()
        {
            var publicData = new
            {
                Message = "This is public data accessible without authentication."
            };
            return Ok(publicData);
        }

        // GET: /api/demo/protected-data
        // This endpoint is secured and requires a valid JWT token.
        [Authorize]
        [HttpGet("protected-data")]
        public IActionResult GetProtectedData()
        {
            var protectedData = new
            {
                Message = "This is protected data accessible only with a valid JWT token."
            };
            return Ok(protectedData);
        }
    }
}
Code Explanation:
  • GetPublicData() is an open API endpoint that returns a simple JSON message without requiring any authentication. This is useful for resources meant to be publicly accessible.
  • GetProtectedData() is secured with the [Authorize] attribute, which means requests to this endpoint must include a valid JWT token in the HTTP Authorization header. If the token is missing or invalid, the server responds with an HTTP 401 Unauthorized status.
Test the Resource Server
Public Endpoint (Accessible without JWT Token):

This endpoint does not require authentication. It returns a message indicating that the data is public.

  • URL: /api/demo/public-data
  • Method: GET
Protected Endpoint (Requires JWT Token):

Requires a valid JWT token in the Authorization header. Returns a message indicating that it’s protected data. Requests missing a valid JWT receive a 401 Unauthorized status.

  • URL: /api/demo/protected-data
  • Method: GET
  • Request Header: Authorization: Bearer <JWT Token>

Implementing a Resource Server using ASP.NET Core Web API with JWT authentication is a robust and industry-standard approach to protecting sensitive data and ensuring that only authorized clients can access your API endpoints.

We have completed our Resource Server Implementation using ASP.NET Core Web API. In the next article, I will discuss how to implement the First Client Application using the ASP.NET Core MVC Project. I hope you enjoy this article on implementing the Resource Server using ASP.NET Core Web API.

Leave a Reply

Your email address will not be published. Required fields are marked *