DEV Community

Nikhil Wagh
Nikhil Wagh

Posted on

Securing ASP.NET Core APIs with OAuth2 and OpenID Connect (2025 Edition)

Security is no longer an afterthought — it’s the foundation. In 2025, with APIs powering everything from mobile apps to AI agents, properly implementing OAuth2 and OpenID Connect (OIDC) in your ASP.NET Core APIs is essential. This guide helps you get it right.

Understanding the Difference

  • OAuth2: A protocol for authorization (who can access what).
  • OpenID Connect (OIDC): An identity layer on top of OAuth2 (who is the user).

They work together: OAuth2 handles permissions; OIDC authenticates the user.

Setup: Required Tools & Libraries

To get started, you'll need:

  • .NET 6+ or .NET 10 (recommended)
  • Microsoft.AspNetCore.Authentication.JwtBearer
  • An Identity Provider (IdP), e.g.,:Azure AD, Auth0, IdentityServer (self-hosted)

Install with:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Enter fullscreen mode Exit fullscreen mode

Step 1: Configure JWT Authentication

In Program.cs:

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://your-idp.com/";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false
        };
    });

Enter fullscreen mode Exit fullscreen mode

Don’t forget to enable authorization middleware:

app.UseAuthentication();
app.UseAuthorization();

Enter fullscreen mode Exit fullscreen mode

Step 2: Protect Your API Endpoints

Use the [Authorize] attribute to protect specific routes:

[Authorize]
[HttpGet("secure-data")]
public IActionResult GetSecureData()
{
    return Ok("You are authenticated!");
}

Enter fullscreen mode Exit fullscreen mode

For role-based access:

[Authorize(Roles = "Admin")]
Enter fullscreen mode Exit fullscreen mode

Or policies:

[Authorize(Policy = "CanAccessReports")]
Enter fullscreen mode Exit fullscreen mode

Step 3: Add Scopes and Policies

In Program.cs:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("CanAccessReports", policy =>
    {
        policy.RequireClaim("scope", "reports.read");
    });
});
Enter fullscreen mode Exit fullscreen mode

Make sure your client includes the reports.read scope when requesting the token.

Step 4: Test with Postman or Swagger

  • Use the Authorization Code Flow in OAuth2
  • Include the token in API calls:
Authorization: Bearer {access_token}
Enter fullscreen mode Exit fullscreen mode

For testing with Postman:

  • Go to “Authorization” tab
  • Set type to OAuth 2.0
  • Configure token URL, client ID, secret, scopes, etc.

Bonus: Token Introspection (Optional)

For APIs that don’t validate JWT locally (e.g., opaque tokens), use introspection:

.AddOAuth2Introspection("introspection", options =>
{
    options.Authority = "https://your-idp.com";
    options.ClientId = "api-client";
    options.ClientSecret = "secret";
});

Enter fullscreen mode Exit fullscreen mode

Refresh Tokens (via OIDC)

To keep users signed in, clients should:

  • Use refresh tokens from the OIDC flow
  • Store them securely
  • Request new access tokens silently

Never expose refresh tokens in browser-based apps!

When to Use What

Scenario Use OAuth2 Use OIDC
Machine-to-Machine API ✅ Yes ❌ No
User Authentication ✅ Yes ✅ Yes
SPA or Mobile App ✅ Yes ✅ Yes
Backend-to-Backend ✅ Yes ❌ No

Real-World Providers You Can Use

Provider Supports OAuth2 + OIDC? Free Tier?
Azure AD ✅ (for dev/test)
Auth0
Okta
IdentityServer Self-hosted

Final Checklist

✔️ JWT authentication enabled
✔️ Authorization middleware active
✔️ Scopes + roles configured
✔️ Secure token storage on client
✔️ HTTPS enforced on all endpoints

Conclusion

OAuth2 and OpenID Connect are not optional anymore — they're table stakes for modern API security. Whether you’re building public APIs or internal enterprise systems, this setup ensures your users and data stay protected.

Top comments (0)