Introduction
In my last article, Building API Gateway Using Ocelot In ASP.NET Core, I introduced how we can use Ocelot to build our API Gateway with the simplest demo. In this article, I will continue with the topic of Building API Gateway In ASP.NET Core and will show you something about authentication later.
As all we know, API services are protected resources. We should secure them as far as we can!
Normally, we will follow Security to handle the security of our projects. This repository contains the security and authorization middleware for ASP.NET Core. It always makes things easier.
Do we need to make a big change when we import API Gateway into our project? The answer is - No! We only make some imperceptible changes. It means that everything will be easy.
Let's look at the below screenshot first.
This screenshot shows that when we want to access our services, the authentication module of API Gateway should be visited at first. We need to visit the auth service to get the access token at first so that we can visit the protected services with the access_token.
Maybe some of you will put the auth service alone,= which means that the clients should visit auth service to get access_token straight at first, then send a request to API Gateway to do something later. There is no doubt that thing will be all right but I recommend that you put your auth service together with other services.
OK, let's begin to do it.
I will use something the same as last article's demo here. I think it may help you to understand more quickly.
Step 1
Create four projects here.
| Project Name | Project Type | Description |
| APIGateway | ASP.NET Core Empty | entry of this demo |
| CustomersAPIServices | ASP.NET Core Web API | API Service that handles something about customers |
| AuthServer | ASP.NET Core Web API | API Service that handles something about auth |
| ClientApp | Console App | This is a Console App that simulates client. |
Make APIGateway and CustomerAPIServices project the same as in the last demo. You can find them in APIGatewayBasicDemo.
Step 2
Finish AuthServer. This service is mainly for generating access_token for the request. What we need to do is add a method to handle this.
- [HttpGet]
- public IActionResult Get(string name, string pwd)
- {
- //just hard code here.
- if (name == "catcher" && pwd == "123")
- {
- var now = DateTime.UtcNow;
- var claims = new Claim[]
- {
- new Claim(JwtRegisteredClaimNames.Sub, name),
- new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
- new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)
- };
- var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_settings.Value.Secret));
- var tokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = signingKey,
- ValidateIssuer = true,
- ValidIssuer = _settings.Value.Iss,
- ValidateAudience = true,
- ValidAudience = _settings.Value.Aud,
- ValidateLifetime = true,
- ClockSkew = TimeSpan.Zero,
- RequireExpirationTime = true,
- };
- var jwt = new JwtSecurityToken(
- issuer: _settings.Value.Iss,
- audience: _settings.Value.Aud,
- claims: claims,
- notBefore: now,
- expires: now.Add(TimeSpan.FromMinutes(2)),
- signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
- );
- var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
- var responseJson = new
- {
- access_token = encodedJwt,
- expires_in = (int)TimeSpan.FromMinutes(2).TotalSeconds
- };
- return Json(responseJson);
- }
- else
- {
- return Json("");
- }
- }
When verifying the users, I just use the hard code here because it's not an important thing to implement it in this article's topic!
We have finished auth service. We can run it up now.

Step 3
Turn to CustomerAPIServices project, we should secure this service!!
Edit the Startup class so that we can enable the authentication. I use JwtBearer here and I set the default authentication scheme to TestKey which I will mention in the next step.
- public void ConfigureServices(IServiceCollection services)
- {
- var audienceConfig = Configuration.GetSection("Audience");
- var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));
- var tokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = signingKey,
- ValidateIssuer = true,
- ValidIssuer = audienceConfig["Iss"],
- ValidateAudience = true,
- ValidAudience = audienceConfig["Aud"],
- ValidateLifetime = true,
- ClockSkew = TimeSpan.Zero,
- RequireExpirationTime = true,
- };
- services.AddAuthentication()
- .AddJwtBearer("TestKey", x =>
- {
- x.RequireHttpsMetadata = false;
- x.TokenValidationParameters = tokenValidationParameters;
- });
- services.AddMvc();
- }
- public void Configure(IApplicationBuilder app)
- {
- app.UseAuthentication();
- app.UseMvc();
- }
And then, we should use Authorize attribute in our method.
- [Authorize]
- [HttpGet]
- public IEnumerable<string> Get()
- {
- return new string[] { "Catcher Wong", "James Li" };
- }
Here, I just authorize of them because we need to show the not protected resources for comparison.
Note
This project is based on ASP.NET Core 2.0. If you are working with 1.x, you may find some difference here. You can follow Migrating Authentication and Identity to ASP.NET Core 2.0 to migrate.
Run it up too!
Step 4
The most important step is now arriving. Configure the authentication in your API Gateway.
- public void ConfigureServices(IServiceCollection services)
- {
- var audienceConfig = Configuration.GetSection("Audience");
- var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));
- var tokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = signingKey,
- ValidateIssuer = true,
- ValidIssuer = audienceConfig["Iss"],
- ValidateAudience = true,
- ValidAudience = audienceConfig["Aud"],
- ValidateLifetime = true,
- ClockSkew = TimeSpan.Zero,
- RequireExpirationTime = true,
- };
- services.AddAuthentication()
- .AddJwtBearer("TestKey", x =>
- {
- x.RequireHttpsMetadata = false;
- x.TokenValidationParameters = tokenValidationParameters;
- });
- services.AddOcelot(Configuration);
- }
You will find that most of the code is the same as Customer Service.
When Ocelot runs, it will look at this ReRoutes AuthenticationOptions.AuthenticationProviderKey and check that there is an Authentication Provider registered with the given key. If there isn't, then Ocelot will not start up. If there is, then the ReRoute will use that provider when it executes.
So, we also should modify the configuration.json file. We should add a new node named AuthenticationOptions and make the AuthenticationProviderKey the same as what we defined in the Startup class.
- {
- "DownstreamPathTemplate": "/api/customers",
- "DownstreamScheme": "http",
- "DownstreamHost": "localhost",
- "DownstreamPort": 9001,
- "UpstreamPathTemplate": "/customers",
- "UpstreamHttpMethod": [ "Get" ],
- "AuthenticationOptions": {
- "AuthenticationProviderKey": "TestKey",
- "AllowedScopes": []
- }
- }
We also run it up now.
Note
If you meet the following error when you run this project, you need to check your code whether the AddJwtBearer method specifies the authentication scheme.
Unhandled Exception: System.InvalidOperationException: Scheme already exists: Bearer
Step 5
We have done all preparation work here. Now, we should use our client app to simulate some request of the API Gateway.
- private static string GetJwt()
- {
- HttpClient client = new HttpClient();
- client.BaseAddress = new Uri( "http://localhost:9000");
- client.DefaultRequestHeaders.Clear();
- var res2 = client.GetAsync("/api/auth?name=catcher&pwd=123").Result;
- dynamic jwt = JsonConvert.DeserializeObject(res2.Content.ReadAsStringAsync().Result);
- return jwt.access_token;
- }
Then, write some code to visit the customer services via API Gateway.
- static void Main(string[] args)
- {
- HttpClient client = new HttpClient();
- client.DefaultRequestHeaders.Clear();
- client.BaseAddress = new Uri("http://localhost:9000");
- // 1. without access_token will not access the service
- // and return 401 .
- var resWithoutToken = client.GetAsync("/customers").Result;
- //print something here
- //2. with access_token will access the service
- // and return result.
- client.DefaultRequestHeaders.Clear();
- var jwt = GetJwt();
- client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");
- var resWithToken = client.GetAsync("/customers").Result;
- //print something here
- //3. visit no auth service
- client.DefaultRequestHeaders.Clear();
- var res = client.GetAsync("/customers/1").Result;
- //print something here
- Console.Read();
- }
When you run this project, you may find the results as follows.
So far, we have done the job.
Here is the source code you can find on my GitHub page.
Summary
This article introduced how to configure authentication when you use Ocelot as your API Gateway. Hope this will help you.
Read next part here >>

Mayank MishraPosted Mar 5, 2021, 9:49 AM
Hi Thanks for Article, i have one question why we need to add Authentication in CustomersAPIServices where APIGayway will be handle Authentication, do we need to add Authentication in each service ??
MJ EbrahimiPosted Sep 10, 2020, 3:05 PM
Good article. For the record, this article was added to this awesome repository. https://github.com/mjebrahimi/Awesome-Microservices-NetCore
Sadat ChowdhuryPosted Aug 13, 2020, 10:48 PM
Hi Wong - I have downloaded the this solution and it is working perfectly in my local machine. But when I hosted in IIS with a real IP but can't access from internet. Could you please help what I need to change so that I can get my micro services from internet.
Bhawesh VermaPosted May 30, 2020, 8:33 AM
Frank Gasparotto - Have you added the "services.AddAuthentication()......" with TestKey in ConfigureServices() method of API Gateway startup class?
Mohd RizwanPosted Mar 18, 2020, 11:54 PM
No need to use jwt validation on API. It will be done on gateway. Gateway will validate all the request.
Juan TapiaPosted Feb 9, 2020, 1:47 PM
Step 2, return JSon???? must a ActionResult
senthil kumarPosted Jan 21, 2020, 10:45 AM
Thank you for the explanation about microservices. Hi Team, I building API with Ocelot microservices. Unfortunately, I'm facing a problem with rerouting. I've created 3 projects[API Gateway, Products, and Customers] based on the attached reference URL [https://www.c-sharpcorner.com/article/building-api-gateway-using-ocelot-in-asp-net-core-part-two/]. On parallel Run the 3 projects. Now I can get the response of customers and products but the API gateway page looks like [This localhost page can’t be found with 404 status]. But when I rewrite the API call in the API gateway URL at that time also it's not working as expected. Kindly help me to resolve this issue why the rerouting is not working +Attached the codes Version: VS 2019 Core 3.1 Platform: Windows
Muhammad SayedPosted Dec 18, 2019, 10:29 AM
Thank you very much for this explanation , it's very helpful , i have a question ...can i check if client has token at API gateway service before redirect to CustomersAPIServices ?
Dennis TaylorPosted Dec 11, 2019, 11:09 AM
Overall, I think this is a good article, but you should try to explain what some of the code is actually doing. It doesn't really help the majority of people coming here for a tutorial to simply tell them to "put some code here...".
Hiber Tadeo Moreno TovillaPosted Dec 5, 2019, 3:52 PM
Hi thank you for share, but I got a doubt what does really mean this part? "Audience": { "Secret": "Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA==", "Iss": "http://www.c-sharpcorner.com/members/catcher-wong", "Aud": "Catcher Wong" }
Ratheesh PSPosted Nov 21, 2019, 11:01 PM
I am getting below error when trying to access the api/customers operation without authentication. Am I missing something? "System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found."
Marcelo OliveiraPosted Oct 6, 2018, 11:28 AM
Hi, Catcher, fantastic article and demo! I have a question for you: how do you make the Ocelot API gateway request the JWT token automatically, so that the client wouldn't have to?
NunoPosted Sep 11, 2018, 7:37 PM
[Authorize] is useless because if you use "AuthenticationOptions" it forces the same as [Authorize] even when not present in the controller's methods.
NunoPosted Sep 11, 2018, 7:35 PM
[Authorize] is useless
KvuongPosted May 5, 2018, 11:26 PM
After checking your demo, I see all services (auth, gateway and customer) have to config same "Audience", what if we what to change this info later? Do we have to copy it over all services?
Gaurav NagriPosted Apr 24, 2018, 10:28 PM
One question here..can an API Gateway re-route to itself i.e can it forward the request to an api hosted within itself?
Fernando AguilarPosted Feb 14, 2018, 10:55 AM
Do you know for what AllowedScopes is used?