Microservices unlock scalability—but they also expose new attack surfaces. Without centralized authentication and authorization, your services are vulnerable.
Enter: IdentityServer + API Gateway (e.g., YARP or Ocelot). This combo lets you:
- Centralize identity management
- Protect each microservice without duplicating logic
- Enforce token validation at the gateway level
In this article, we’ll walk through a production-grade setup to secure your .NET microservices using OAuth2, OpenID Connect, and IdentityServer—with a gateway enforcing access.
Architecture Overview
[Browser / SPA / Mobile]
↓
[IdentityServer (Auth)]
↓ ↘
[API Gateway] → [Microservice A]
↓ [Microservice B]
↓
[Token Validation + Routing]
Components:
- IdentityServer (OIDC server): Issues and validates access tokens
- API Gateway (Ocelot/YARP): Front-door for all services, validates tokens
- Microservices: Contain business logic, trust tokens from gateway
Step 1: Set Up IdentityServer
Use Duende IdentityServer
for full OpenID Connect compliance.
Sample Client & API Configuration:
public static IEnumerable<Client> GetClients() =>
new[]
{
new Client
{
ClientId = "gateway",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = { new Secret("supersecret".Sha256()) },
AllowedScopes = { "orders.read", "inventory.write" }
}
};
public static IEnumerable<ApiScope> GetApiScopes() =>
new[]
{
new ApiScope("orders.read"),
new ApiScope("inventory.write")
};
- Client: API Gateway itself
- Scopes: Define fine-grained access control
Step 2: Configure API Gateway (Ocelot or YARP)
Token Validation Middleware in YARP:
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://identity.mycompany.com";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
builder.Services.AddAuthorization();
builder.Services.AddReverseProxy()
.LoadFromConfig(Configuration.GetSection("ReverseProxy"));
Now secure each route via policy:
"Routes": [
{
"RouteId": "orders",
"ClusterId": "ordersApi",
"AuthorizationPolicy": "AuthenticatedUsersOnly",
"Match": { "Path": "/orders/{**catch-all}" },
"Transforms": [ ... ]
}
]
Step 3: Protect Downstream Microservices
Each service should trust the gateway and validate tokens.
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://identity.mycompany.com";
options.RequireHttpsMetadata = true;
options.Audience = "orders"; // Optional for resource-based auth
});
Add [Authorize]
to protected endpoints.
[Authorize]
[HttpGet("/orders")]
public IActionResult GetOrders() => ...
Advanced Features You Can Add
- Token Refresh for SPA clients
- Role-based / policy-based auth via claims
- Rate limiting & circuit breakers in the gateway
- Audit logging for security compliance
- External Identity Providers (Google, Azure AD)
Testing It All
- Authenticate using IdentityServer, get access token
- Call gateway with Authorization: Bearer
- Gateway validates token, routes to service
- Microservice optionally revalidates and applies auth rules
Use tools like Postman, curl, or Swagger UI with OAuth2 for testing.
Summary
Securing microservices isn’t just about firewalls—it’s about trust boundaries and token validation. With IdentityServer and API Gateway:
- You authenticate once, and propagate access securely
- You centralize policies, reducing code duplication
- You build a resilient and secure architecture that scales
What’s Your Security Setup?
Are you using OAuth2 or JWTs to protect your services? Drop your experience, pain points, or questions in the comments!
Top comments (0)