Back to: ASP.NET Core Web API Tutorials
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.
Implementing Resource Server using ASP.NET Core Web API
Let’s build the Resource Server Application using ASP.NET Core Web API with JWT authentication. A Resource Server is an API that hosts protected resources (data) and enforces security by validating JWT tokens on incoming requests. In our implementation, we will create two endpoints:
- Public Endpoint: Accessible without any authentication.
- Protected Endpoint: Accessible only when a valid JWT token is provided.
This approach demonstrates how JWT authentication can be integrated into an ASP.NET Core Web API to secure your endpoints.
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 Package via the Package Manager Console by executing the below 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 the AppSettings.json file:
Open the appsettings.json file and insert the following configuration settings. These settings provide the secret key, issuer, and audience information used when validating incoming JWT tokens:
{ "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 "Audience": "http://localhost:7035" //Client Application Domain URL Base Address } }
Key Points:
- Key: A secret string used to validate the token’s signature. This ensures that only tokens signed with this key are considered valid.
- Issuer: The origin or authority that issued the token. The Resource Server can check that incoming tokens come from the expected source. When validating a token, this value should match.
- Audience: The intended recipient of the token. This helps ensure that a token meant for one application is not misused by another. It ensures that the correct recipient uses the token.
Configure JWT Authentication in the Resource Server
Next, modify the Program.cs file to set up JWT authentication. Here, we have registered the JWT authentication schema to be used and provided the logic based on which the JWT token will be validated.
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 and challenge schemes to JWT Bearer. options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { // Configure how the JWT token is validated. options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, // Set to true if you want to ensure the token issuer is valid. 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"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; }); // 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(); } // Enforce HTTPS for secure communications. app.UseHttpsRedirection(); // Add the authentication and authorization middleware. app.UseAuthentication(); app.UseAuthorization(); // Map controller endpoints. app.MapControllers(); app.Run(); } } }
Code Explanations:
- Authentication Setup: Configures the application to use JWT Bearer tokens for authenticating requests.
- Token Validation: The TokenValidationParameters specify how tokens are checked, including validating the signature, expiration, and optionally the issuer and audience.
- Middleware Order: It’s important that app.UseAuthentication() comes before app.UseAuthorization() so that the authentication middleware processes requests and populates the user context before authorization checks occur.
Creating Demo Controller
Next, create a new API Empty controller named DemoController.cs within the Controllers folder and copy and paste the following code. Here, we have created two endpoints: The PublicData Endpoint is Accessible without authentication. ProtectedData Endpoint Requires a valid JWT token for access.
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(): Returns a simple JSON message and is accessible without authentication. This is useful for public resources.
- GetProtectedData(): Decorated with the [Authorize] attribute, this endpoint requires that the incoming request include a valid JWT token. The server will return a 401 Unauthorized status if the token is missing or invalid.
Test the Resource Server
Public Endpoint (Accessible without JWT Token):
This endpoint does not require authentication. It returns a message indicating that it’s public data.
URL: /api/demo/public-data
Method: GET
Response:
{ "Message": "This is public data accessible without authentication." }
Protected Endpoint (Requires JWT Token):
A valid JWT token is required 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 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJQcmFuYXlhIiwianRpIjoiMWFmZWI5NjItNThiZi00MjUyLTkxYjktY2M4OWE0MThmYzc4IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiJhMWYyOTg3OS00YmYxLTQ1NTQtODY2OC03MTJlOThhYzNmOGEiLCJleHAiOjE3MjQ0NzgyNzEsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0OjcwMzUiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjcwMzUifQ.9U9_sHnhMztzcN1QdzhhXQObkKULQuScYOyASpIhFJI
Response (with valid JWT token):
{ "Message": "This is protected data accessible only with a valid JWT token." }
That’s it. We are done with 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 how to Implement the Resource Server using ASP.NET Core Web API.