{"id":88327,"date":"2023-05-08T08:00:11","date_gmt":"2023-05-08T06:00:11","guid":{"rendered":"https:\/\/drafts.code-maze.com\/?p=88327"},"modified":"2024-07-22T12:26:27","modified_gmt":"2024-07-22T10:26:27","slug":"dotnetcore-secure-microservices-jwt-ocelot","status":"publish","type":"post","link":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/","title":{"rendered":"Secure Microservices Using JWT With Ocelot in .NET Core"},"content":{"rendered":"<p>Microservices are a common design pattern nowadays in software applications. Moreover, we usually have some sort of API Gateway, such as Ocelot, to provide a single API for consumers of our microservices and encapsulate underlying implementation details and handle authentication, which is often implemented with JWT.<\/p>\n<p>In this article, we are going to explore how we secure our microservices behind the Ocelot API Gateway by using JWT authentication.<\/p>\n<p>Note &#8211; we aren&#8217;t going to cover the finer details of setting up JWT authentication or an Ocelot API Gateway. We recommend you check out our great articles on <a href=\"https:\/\/code-maze.com\/authentication-aspnetcore-jwt-1\/\" target=\"_blank\" rel=\"noopener\">JWT Authentication<\/a> and <a href=\"https:\/\/code-maze.com\/aspnetcore-api-gateway-with-ocelot\/\" target=\"_blank\" rel=\"noopener\">Ocelot API Gateway<\/a> before diving into this one.<\/p>\n<div style=\"padding: 20px; border-left: 5px color:#dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">To download the source code for the video, visit our <a href=\"https:\/\/www.patreon.com\/posts\/source-code-jwt-108588928?src=SecureMicroservicesUsingJWTOcelot\" target=\"_blank\" rel=\"nofollow noopener\">Patreon page<\/a> (YouTube Patron tier).<\/div>\n<p>With that, let&#8217;s start.<\/p>\n<hr \/>\r\n<p style=\"text-align: center;\"><strong>VIDEO<\/strong>: Secure Microservices Using JWT With Ocelot in .NET Core.<\/p>\r\n<p style=\"text-align: center;\"><iframe width=\"560\" height=\"315\" src=https:\/\/www.youtube.com\/embed\/mf4-Jr_KGQA?si=9lKK_zirg5MpzUy8 frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\r\n<hr \/>\n<h2>Create Microservice<\/h2>\n<p>Before we look at setting up JWT authentication with Ocelot, we need a microservice to validate that our authentication works as expected. To start, let&#8217;s create a new ASP.NET Core Web API using the Visual Studio Project wizard or the\u00a0<code>dotnet new webapi<\/code> command.<\/p>\n<p>Our microservice&#8217;s domain will be shoes, so let&#8217;s create a basic model for this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class Shoe\r\n{\r\n    public required int Id { get; set; }\r\n\r\n    public required string Name { get; set; }\r\n\r\n    public required string Brand { get; set; }\r\n\r\n    public decimal Price { get; set; }\r\n}<\/pre>\n<p>Here we define some <a href=\"https:\/\/code-maze.com\/csharp-required-members\/\" target=\"_blank\" rel=\"noopener\">required members<\/a> for our model.<\/p>\n<p>Next, we&#8217;ll create a repository to allow us to interact with our shoes:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class ShoeRepository : IShoeRepository\r\n{\r\n    private static List&lt;Shoe&gt; _shoes = new()\r\n    {\r\n        new()\r\n        {\r\n            Id = 1,\r\n            Name = \"Pegasus 39\",\r\n            Brand = \"Nike\",\r\n            Price = 119.99M\r\n        },\r\n        new()\r\n        {\r\n            Id = 2,\r\n            Name = \"Vaporfly\",\r\n            Brand = \"Nike\",\r\n            Price = 229.99M\r\n        },\r\n        new()\r\n        {\r\n            Id = 3,\r\n            Name = \"Ride 15\",\r\n            Brand = \"Saucony\",\r\n            Price = 119.99M\r\n        }\r\n    };\r\n\r\n    public List&lt;Shoe&gt; GetShoes() =&gt; _shoes;\r\n\r\n    public bool DeleteShoe(int id)\r\n    {\r\n        var shoe = _shoes.FirstOrDefault(s =&gt; s.Id == id);\r\n\r\n        if (shoe is not null)\r\n        {\r\n            return _shoes.Remove(shoe);\r\n        }\r\n\r\n        return false;\r\n    }\r\n}<\/pre>\n<p>For the purposes of this article, we&#8217;ll simply store our shoes in memory as a list.<\/p>\n<p>Here, we implement the\u00a0<code>IShoeRepository<\/code> interface, which has two methods defined, <code>GetShoes()<\/code> and <code>DeleteShoe()<\/code>. These methods will allow us to test out our authentication later on.<\/p>\n<p>We need to register this interface with the <a href=\"https:\/\/code-maze.com\/dependency-injection-aspnet\/\" target=\"_blank\" rel=\"noopener\">dependency injection<\/a> framework in the <code>Program<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"5\">var builder = WebApplication.CreateBuilder(args);\r\n\r\n\/\/ code removed for brevity\r\n\r\nbuilder.Services.AddScoped&lt;IShoeRepository, ShoeRepository&gt;();\r\n\r\nvar app = builder.Build();\r\n\r\n\/\/ code removed for brevity \r\n\r\napp.Run();<\/pre>\n<p>Finally, we&#8217;ll expose an API for our microservice so we can interact with it over <a href=\"https:\/\/code-maze.com\/http-series-part-1\/\" target=\"_blank\" rel=\"noopener\">HTTP<\/a>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Route(\"api\/[controller]\")]\r\n[ApiController]\r\npublic class ShoesController : ControllerBase\r\n{\r\n    private readonly IShoeRepository _shoeRepository;\r\n\r\n    public ShoesController(IShoeRepository shoeRepository)\r\n    {\r\n        _shoeRepository = shoeRepository;\r\n    }\r\n\r\n    [HttpGet]\r\n    public IActionResult Get()\r\n    {\r\n        return Ok(_shoeRepository.GetShoes());\r\n    }\r\n\r\n    [HttpDelete(\"{id:int}\")]\r\n    public IActionResult Delete(int id)\r\n    {\r\n        var shoeDeleted = _shoeRepository.DeleteShoe(id);\r\n\r\n        return shoeDeleted ? NoContent() : NotFound();\r\n    }\r\n}<\/pre>\n<p>First, we create a private property for our\u00a0<code>IShoeRepository<\/code> interface, which we inject into the class constructor.<\/p>\n<p>Then, we define two API methods to reflect the methods exposed from our repository class.<\/p>\n<p>Before we configure Ocelot to use JWT authentication, let&#8217;s verify we can communicate with our Shoe microservice through Ocelot.<\/p>\n<h3>Route Microservice Through Ocelot<\/h3>\n<p>In our Ocelot project, let&#8217;s add the routes for the Shoe microservice to the\u00a0<code>ocelot.json<\/code> configuration file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\r\n  \"Routes\": [\r\n    {\r\n      \"UpstreamPathTemplate\": \"\/shoes\",\r\n      \"UpstreamHttpMethod\": [ \"Get\" ],\r\n      \"DownstreamPathTemplate\": \"\/api\/shoes\",\r\n      \"DownstreamScheme\": \"https\",\r\n      \"DownstreamHostAndPorts\": [\r\n        {\r\n          \"Host\": \"localhost\",\r\n          \"Port\": 5001\r\n        }\r\n      ]\r\n    },\r\n    {\r\n      \"UpstreamPathTemplate\": \"\/shoes\/{id}\",\r\n      \"UpstreamHttpMethod\": [ \"Delete\" ],\r\n      \"DownstreamPathTemplate\": \"\/api\/shoes\/{id}\",\r\n      \"DownstreamScheme\": \"https\",\r\n      \"DownstreamHostAndPorts\": [\r\n        {\r\n          \"Host\": \"localhost\",\r\n          \"Port\": 5001\r\n        }\r\n      ]\r\n    }\r\n  ],\r\n  \"GlobalConfiguration\": {\r\n    \"BaseUrl\": \"https:\/\/localhost:5000\"\r\n  }\r\n}<\/pre>\n<p>Here, we define two separate routes. One for our <code>GET<\/code> method, and one for our <code>DELETE<\/code> method in our Shoe microservice.<\/p>\n<p>Finally, we must remember to include the <code>BaseUrl<\/code> for our Ocelot gateway, which will be the same URL as what is configured in our\u00a0<code>launchSettings.json<\/code> file.<\/p>\n<p>We haven&#8217;t gone through the setup of the Ocelot project in this article, as we have articles that cover that in great detail. Please refer to the source code for this article to see the basic configuration <strong>(link directly to the Ocelot project)<\/strong>.<\/p>\n<p>Now that we have our microservice created and our Ocelot gateway configured, let&#8217;s run both applications and make a request to <code>https:\/\/localhost:5000\/shoes<\/code> which will return our list of shoes through our Ocelot gateway. Also, we can confirm our delete method works by making a delete request to <code>\/shoes\/1<\/code> to delete the shoe with ID 1.<\/p>\n<p>Great! We have our gateway configured correctly to handle requests to our Shoe microservice. Next, let&#8217;s explore how we add JWT authentication to our application.<\/p>\n<h2>Secure Ocelot With JWT Authentication<\/h2>\n<p><strong>Ocelot provides various ways to configure authentication, with JWT being one of them<\/strong>. So, let&#8217;s start to incorporate JWT authentication into our gateway and microservice combination.<\/p>\n<p>To start, we need a way to generate JWT tokens. We don&#8217;t want to store this logic in our gateway or microservice, so we&#8217;ll create a separate API project for authentication, again using the Visual Studio Project wizard or the <code>dotnet new webapi<\/code> command.<\/p>\n<h3>Configure JWT Authentication<\/h3>\n<p>With our project created, let&#8217;s create a <a href=\"https:\/\/code-maze.com\/csharp-records\/\">record<\/a> to model a user:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public record User(string Username, string Password, string Role, string[] Scopes);<\/code><\/p>\n<p>Here, we have a very simple user model with a\u00a0<code>Username<\/code>,\u00a0<code>Password<\/code> ,<code>Role<\/code>, and\u00a0<code>Scope<\/code> property. The last two properties will be used when we look at advanced authorization for Ocelot.<\/p>\n<p>Now, let&#8217;s create a service to generate our JWT:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class JwtTokenService\r\n{\r\n    private readonly List&lt;User&gt; _users = new()\r\n    {\r\n        new(\"admin\", \"aDm1n\", \"Administrator\", new[] {\"shoes.read\"}),\r\n        new(\"user01\", \"u$3r01\", \"User\", new[] {\"shoes.read\"})\r\n    };\r\n\r\n    public AuthenticationToken? GenerateAuthToken(LoginModel loginModel)\r\n    {\r\n        var user = _users.FirstOrDefault(u =&gt; u.Username == loginModel.Username \r\n                                           &amp;&amp; u.Password == loginModel.Password);\r\n\r\n        if (user is null)\r\n        {\r\n            return null;\r\n        }\r\n\r\n        var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtExtensions.SecurityKey));\r\n        var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);\r\n        var expirationTimeStamp = DateTime.Now.AddMinutes(5);\r\n\r\n        var claims = new List&lt;Claim&gt;\r\n        {\r\n            new Claim(JwtRegisteredClaimNames.Name, user.Username),\r\n            new Claim(\"role\", user.Role),\r\n            new Claim(\"scope\", string.Join(\" \", user.Scopes)) \r\n        };\r\n\r\n        var tokenOptions = new JwtSecurityToken(\r\n            issuer: \"https:\/\/localhost:5002\",\r\n            claims: claims,\r\n            expires: expirationTimeStamp,\r\n            signingCredentials: signingCredentials\r\n        );\r\n\r\n        var tokenString = new JwtSecurityTokenHandler().WriteToken(tokenOptions);\r\n\r\n        return new AuthenticationToken(tokenString, (int)expirationTimeStamp.Subtract(DateTime.Now).TotalSeconds);\r\n    }\r\n}\r\n<\/pre>\n<p>We won&#8217;t go into depth in this article on all the configurations for JWT. Check out the previously linked article if you&#8217;d like to learn more about this.<\/p>\n<p>Saying that there are a couple of things worth mentioning. First is our list of users which we&#8217;ll use to validate if a login attempt is valid.<\/p>\n<p>Secondly, we add the <code>Role<\/code> and\u00a0<code>Scope<\/code> properties of the user to the claims collection, and we&#8217;ll see that in use later.<\/p>\n<p>Finally, we set the issuer to\u00a0<code>https:\/\/localhost:5002<\/code> which is the port our Authentication API will be listening on.<\/p>\n<p>We can now use this token service to create our Authentication API controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class AuthController : ControllerBase\r\n{\r\n    private readonly JwtTokenService _jwtTokenService;\r\n\r\n    public AuthController(JwtTokenService jwtTokenService)\r\n    {\r\n        _jwtTokenService = jwtTokenService;\r\n    }\r\n\r\n    [HttpPost]\r\n    public IActionResult Login([FromBody] LoginModel user)\r\n    {\r\n        var loginResult = _jwtTokenService.GenerateAuthToken(user);\r\n\r\n        return loginResult is null ? Unauthorized() : Ok(loginResult);\r\n    }\r\n}<\/pre>\n<p>Here, we have a single <code>POST<\/code> endpoint for login attempts. If the login attempt is unsuccessful, we return\u00a0<code>401 Unauthorized<\/code> otherwise we return the valid JWT.<\/p>\n<p>With our Authentication API created, next, we&#8217;ll create a class library as we&#8217;ll share the registration code between our gateway and microservice. Within this class library, let&#8217;s create an extension method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public static class JwtExtensions\r\n{\r\n    public const string SecurityKey = \"secretJWTsigningKey@123\";\r\n\r\n    public static void AddJwtAuthentication(this IServiceCollection services)\r\n    {\r\n        services.AddAuthentication(opt =&gt; {\r\n            opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\r\n            opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\r\n        })\r\n        .AddJwtBearer(options =&gt;\r\n        {\r\n            options.TokenValidationParameters = new TokenValidationParameters\r\n            {\r\n                ValidateIssuer = true,\r\n                ValidIssuer = \"https:\/\/localhost:5002\",\r\n                ValidateAudience = false,\r\n                ValidateIssuerSigningKey = true,\r\n                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey))\r\n            };\r\n        });\r\n    }\r\n}<\/pre>\n<p>Here, we configure the JWT authentication scheme. In the <code>AddJwtBearer()<\/code> method, we set our signing key and ensure we use our Authentication API as the\u00a0<code>ValidIssuer<\/code>.<\/p>\n<p>Now we can use this extension method in our microservice and Ocelot gateway in the <code>Program<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"5, 11-12\">var builder = WebApplication.CreateBuilder(args);\r\n\r\n\/\/ code removed for brevity\r\n\r\nbuilder.Services.AddJwtAuthentication();\r\n\r\nvar app = builder.Build();\r\n\r\n\/\/ code removed for brevity\r\n\r\napp.UseAuthentication();\r\napp.UseAuthorization();\r\n\r\napp.Run();<\/pre>\n<p>First, we call the\u00a0<code>AddJwtAuthentication()<\/code> method as part of the service registration. Also, we call the\u00a0<code>UseAuthentication()<\/code> and <code>UseAuthorization()<\/code> methods to ensure our applications correctly use the JWT authentication scheme.<\/p>\n<h3>Protect Microservice Through Ocelot With JWT Authentication<\/h3>\n<p>The final thing we need to do to configure Ocelot to secure our microservice is to set up the authentication in <code>ocelot.json<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-highlight=\"3-14,27-28\">{\r\n  \"Routes\": [\r\n    {\r\n      \"UpstreamPathTemplate\": \"\/auth\",\r\n      \"UpstreamHttpMethod\": [ \"Post\" ],\r\n      \"DownstreamScheme\": \"https\",\r\n      \"DownstreamPathTemplate\": \"\/api\/auth\",\r\n      \"DownstreamHostAndPorts\": [\r\n        {\r\n          \"Host\": \"localhost\",\r\n          \"Port\": 5002\r\n        }\r\n      ]\r\n    },\r\n    \/\/ code removed for brevity\r\n    {\r\n      \"UpstreamPathTemplate\": \"\/shoes\/{id}\",\r\n      \"UpstreamHttpMethod\": [ \"Delete\" ],\r\n      \"DownstreamPathTemplate\": \"\/api\/shoes\/{id}\",\r\n      \"DownstreamScheme\": \"https\",\r\n      \"DownstreamHostAndPorts\": [\r\n        {\r\n          \"Host\": \"localhost\",\r\n          \"Port\": 5001\r\n        }\r\n      ],\r\n      \"AuthenticationOptions\": {\r\n        \"AuthenticationProviderKey\": \"Bearer\"\r\n      }\r\n    }\r\n  ]\r\n}<\/pre>\n<p>First, we add our Authentication API from earlier, so requests are routed through Ocelot.<\/p>\n<p>Next, we only want to protect our delete endpoint from unauthorized access, so we <strong>add the <code>AuthenticationOptions<\/code> section to our delete route<\/strong>. In this section, we define <strong>the provider key as\u00a0<code>Bearer<\/code>. This tells Ocelot to check for the\u00a0<code>Bearer<\/code> authentication scheme by validating if the user is authorized.<\/strong><\/p>\n<p>Let&#8217;s run our application and make a request to\u00a0<code>\/shoes<\/code> which will still return our list of shoes as expected. Next, let&#8217;s try to make an unauthenticated request to\u00a0<code>\/shoes\/1<\/code>. This time it will fail with a <code>401 Unauthorized<\/code> <a href=\"https:\/\/code-maze.com\/http-series-part-1\/#statuscodes\" target=\"_blank\" rel=\"noopener\">status code<\/a>, which proves our JWT authentication is working as expected and securing our microservice.<\/p>\n<p>Now, let&#8217;s retrieve a JWT from our Authentication API by making a request to <code>\/auth<\/code>, providing a valid user in the body:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{ \"username\": \"admin\", \"password\": \"aDm1n\" }<\/code><\/p>\n<p>Our API will return a valid token which we can now use in our delete request, ensuring we pass it in the <code>Authorization<\/code> header with the\u00a0<code>Bearer<\/code> token type. This time, we receive a <code>204 NoContent<\/code> meaning we have successfully deleted a shoe. We can confirm this by making another request to\u00a0<code>\/shoes<\/code> where we&#8217;ll only retrieve 2 shoes instead of 3.<\/p>\n<p>Excellent! We&#8217;ve secured our microservice that sits behind an Ocelot API gateway with JWT authentication. Next, let&#8217;s look at some of the more advanced options we have for securing our microservices with Ocelot.<\/p>\n<h2>JWT Scope-Based Authorization With Ocelot<\/h2>\n<p><strong>Ocelot allows us to secure our endpoints using scopes<\/strong>, checking if the authenticated request has the correct scope before sending the request to our microservice.<\/p>\n<p>When we generate our JWT, we add the <code>scope<\/code> claim, so let&#8217;s use this to protect our <code>GET<\/code> endpoint in <code>ocelot.json<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-highlight=\"15-18\">{\r\n  \"Routes\": [\r\n   \/\/ code removed for brevity \r\n    {\r\n      \"UpstreamPathTemplate\": \"\/shoes\",\r\n      \"UpstreamHttpMethod\": [ \"Get\" ],\r\n      \"DownstreamPathTemplate\": \"\/api\/shoes\",\r\n      \"DownstreamScheme\": \"https\",\r\n      \"DownstreamHostAndPorts\": [\r\n        {\r\n          \"Host\": \"localhost\",\r\n          \"Port\": 5001\r\n        }\r\n      ],\r\n      \"AuthenticationOptions\": {\r\n        \"AuthenticationProviderKey\": \"Bearer\",\r\n        \"AllowedScopes\": [\"shoes.read\"]\r\n      }\r\n    }\r\n    \/\/ code removed for brevity \r\n  ]\r\n}<\/pre>\n<p>Here, we add the\u00a0<code>AuthenticationOptions<\/code> section to our <code>GET<\/code> endpoint, once again requiring the\u00a0<code>Bearer<\/code> provider key. This time, we add the\u00a0<code>AllowedScopes<\/code> key, which accepts an array of scopes. We use our\u00a0<code>shoes.read<\/code> scope, which both our users have assigned.<\/p>\n<p>Let&#8217;s test this out by generating a JWT with one of our users, and making a request to <code>\/shoes<\/code> which will return our list of shoes as expected.<\/p>\n<p><strong>If the user doesn&#8217;t have the correct scope assigned, Ocelot returns a <code>403 Forbidden<\/code><\/strong>.<\/p>\n<p>With this, we can secure multiple endpoints and restrict access to users with the correct scopes only.<\/p>\n<h2>JWT Role-Based Authorization With Ocelot<\/h2>\n<p><strong>Ocelot provides claims-based authorization which we can use to further protect our microservices.<\/strong><\/p>\n<p>When we defined our\u00a0<code>User<\/code> model, we provided a\u00a0<code>Role<\/code> property, which we can use to restrict access to certain endpoints in our microservice. Let&#8217;s set up a restriction so that only users with the\u00a0<code>Administrator<\/code> role can delete shoes:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-highlight=\"18-20\">{\r\n  \"Routes\": [\r\n    \/\/ code removed for brevity\r\n    {\r\n      \"UpstreamPathTemplate\": \"\/shoes\/{id}\",\r\n      \"UpstreamHttpMethod\": [ \"Delete\" ],\r\n      \"DownstreamPathTemplate\": \"\/api\/shoes\/{id}\",\r\n      \"DownstreamScheme\": \"https\",\r\n      \"DownstreamHostAndPorts\": [\r\n        {\r\n          \"Host\": \"localhost\",\r\n          \"Port\": 5001\r\n        }\r\n      ],\r\n      \"AuthenticationOptions\": {\r\n        \"AuthenticationProviderKey\": \"Bearer\"\r\n      },\r\n      \"RouteClaimsRequirement\": {\r\n        \"role\": \"Administrator\"\r\n      }\r\n    }\r\n  ]\r\n}<\/pre>\n<p>Here, we add the\u00a0<code>RouteClaimsRequirement<\/code> section, providing the\u00a0<code>role<\/code> key with the <code>Administrator<\/code> value. <strong>This<\/strong> <strong>tells<\/strong> <strong>Ocelot to check each request for the\u00a0<code>role<\/code> claim in the JWT, and only allow requests with the <code>Administrator<\/code> value to pass through<\/strong>.<\/p>\n<p>Let&#8217;s put this theory to the test. Running our application, this time we&#8217;ll log in as a user with the <code>User<\/code> role:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{ \"username\": \"user01\", \"password\": \"u$3r01\" }<\/code><\/p>\n<p>As we haven&#8217;t restricted access to the GET endpoint, we can still make requests to\u00a0<code>\/shoes<\/code> and retrieve our list of shoes. However, when we make a delete request to\u00a0<code>\/shoes\/1<\/code>, we receive a <code>403 Forbidden<\/code>.<\/p>\n<p>Now let&#8217;s generate a JWT as an administrator and make the same request. This time we receive a <code>204 NoContent<\/code> as expected, and our shoe with ID 1 is deleted successfully.<\/p>\n<h2>Conclusion<\/h2>\n<p>Securing our microservices is vitally important if we don&#8217;t want unauthorized users to access sensitive data. In this article, we looked at how to secure microservices that use the Ocelot Gateway with JWT authentication. First, we saw how to restrict all access if the user is unauthenticated, and then explored scoped-based and role-based authorization and how we configure Ocelot to handle this for us.<\/p>\n<p>This keeps authorization logic out of our microservice and allows us to store the authorization configuration in a single, easy-to-manage location.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Microservices are a common design pattern nowadays in software applications. Moreover, we usually have some sort of API Gateway, such as Ocelot, to provide a single API for consumers of our microservices and encapsulate underlying implementation details and handle authentication, which is often implemented with JWT. In this article, we are going to explore how [&hellip;]<\/p>\n","protected":false},"author":39,"featured_media":62193,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[2081,1512,1806],"tags":[826,75,827,1246,72],"class_list":["post-88327","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-client-library","category-microservices","category-security","tag-api-gateway","tag-jwt","tag-microservices","tag-ocelot","tag-security","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Secure Microservices Using JWT With Ocelot in .NET Core<\/title>\n<meta name=\"description\" content=\"In this article, we are going to explore how to set up Ocelot API Gateway to use JWT authentication to secure our microservices.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Secure Microservices Using JWT With Ocelot in .NET Core\" \/>\n<meta property=\"og:description\" content=\"In this article, we are going to explore how to set up Ocelot API Gateway to use JWT authentication to secure our microservices.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2023-05-08T06:00:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-07-22T10:26:27+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Phil Broderick\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Phil Broderick\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\"},\"author\":{\"name\":\"Phil Broderick\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/77436f727e1038cfd00e47dc22f07158\"},\"headline\":\"Secure Microservices Using JWT With Ocelot in .NET Core\",\"datePublished\":\"2023-05-08T06:00:11+00:00\",\"dateModified\":\"2024-07-22T10:26:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\"},\"wordCount\":1575,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png\",\"keywords\":[\"API Gateway\",\"jwt\",\"Microservices\",\"Ocelot\",\"security\"],\"articleSection\":[\"Client Library\",\"Microservices\",\"Security\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\",\"url\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\",\"name\":\"Secure Microservices Using JWT With Ocelot in .NET Core\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png\",\"datePublished\":\"2023-05-08T06:00:11+00:00\",\"dateModified\":\"2024-07-22T10:26:27+00:00\",\"description\":\"In this article, we are going to explore how to set up Ocelot API Gateway to use JWT authentication to secure our microservices.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png\",\"width\":1100,\"height\":620,\"caption\":\".NET Security\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Secure Microservices Using JWT With Ocelot in .NET Core\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/77436f727e1038cfd00e47dc22f07158\",\"name\":\"Phil Broderick\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/03\/phil-300x-300x-150x150.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/03\/phil-300x-300x-150x150.png\",\"caption\":\"Phil Broderick\"},\"description\":\"A software developer based in the UK specializing in modernizing legacy systems and building cloud-native applications. Phil loves to gain knowledge from those around him and share his own by co-running an Azure-focused Meetup group and regularly giving talks and demos. When not exploring new Cloud technologies, Phil is an avid runner and more recently cyclist, hoping to dive into the world of Triathlons in the near future.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/phil-broderick\"],\"url\":\"https:\/\/code-maze.com\/author\/philbroderick\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Secure Microservices Using JWT With Ocelot in .NET Core","description":"In this article, we are going to explore how to set up Ocelot API Gateway to use JWT authentication to secure our microservices.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/","og_locale":"en_US","og_type":"article","og_title":"Secure Microservices Using JWT With Ocelot in .NET Core","og_description":"In this article, we are going to explore how to set up Ocelot API Gateway to use JWT authentication to secure our microservices.","og_url":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/","og_site_name":"Code Maze","article_published_time":"2023-05-08T06:00:11+00:00","article_modified_time":"2024-07-22T10:26:27+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png","type":"image\/png"}],"author":"Phil Broderick","twitter_card":"summary_large_image","twitter_creator":"@CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Phil Broderick","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/"},"author":{"name":"Phil Broderick","@id":"https:\/\/code-maze.com\/#\/schema\/person\/77436f727e1038cfd00e47dc22f07158"},"headline":"Secure Microservices Using JWT With Ocelot in .NET Core","datePublished":"2023-05-08T06:00:11+00:00","dateModified":"2024-07-22T10:26:27+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/"},"wordCount":1575,"commentCount":2,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png","keywords":["API Gateway","jwt","Microservices","Ocelot","security"],"articleSection":["Client Library","Microservices","Security"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/","url":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/","name":"Secure Microservices Using JWT With Ocelot in .NET Core","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png","datePublished":"2023-05-08T06:00:11+00:00","dateModified":"2024-07-22T10:26:27+00:00","description":"In this article, we are going to explore how to set up Ocelot API Gateway to use JWT authentication to secure our microservices.","breadcrumb":{"@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-dotnet-security.png","width":1100,"height":620,"caption":".NET Security"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/dotnetcore-secure-microservices-jwt-ocelot\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"Secure Microservices Using JWT With Ocelot in .NET Core"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/77436f727e1038cfd00e47dc22f07158","name":"Phil Broderick","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/03\/phil-300x-300x-150x150.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/03\/phil-300x-300x-150x150.png","caption":"Phil Broderick"},"description":"A software developer based in the UK specializing in modernizing legacy systems and building cloud-native applications. Phil loves to gain knowledge from those around him and share his own by co-running an Azure-focused Meetup group and regularly giving talks and demos. When not exploring new Cloud technologies, Phil is an avid runner and more recently cyclist, hoping to dive into the world of Triathlons in the near future.","sameAs":["https:\/\/www.linkedin.com\/in\/phil-broderick"],"url":"https:\/\/code-maze.com\/author\/philbroderick\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/88327","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=88327"}],"version-history":[{"count":5,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/88327\/revisions"}],"predecessor-version":[{"id":120821,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/88327\/revisions\/120821"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/62193"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=88327"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=88327"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=88327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}