Authentication with OAuth2 (Without OpenID Connect) in .NET Core with an Item API
No need your passwords for next time.
OAuth2 is widely used for authorization in web applications, allowing third-party services to access resources on behalf of a user without exposing their credentials. In this blog, we'll explore how to implement OAuth2 authentication in a .NET Core application, focusing on securing an Item API without using OpenID Connect (OIDC).
What is OAuth2?
OAuth2 is an open standard protocol for authorization, providing a secure way for users to grant third-party applications access to their resources without sharing their credentials. OAuth2 is commonly used for token-based authentication and access control.
Why Use OAuth2 Without OIDC?
While OpenID Connect (OIDC) is often used alongside OAuth2 to add user authentication and identity management, there are cases where you might want to use OAuth2 alone, such as when:
You only need to authorize access to resources, not authenticate users.
Your application doesn't require the identity information provided by OIDC.
Implementing OAuth2 in a .NET Core Application
Let's walk through the implementation of OAuth2 in a .NET Core application using an Item API as an example.
1. Setting Up an OAuth2 Authorization Server
Before implementing OAuth2 in your .NET Core application, you need an OAuth2 authorization server. This server is responsible for issuing access tokens to clients after they successfully authenticate.
You can use existing services like Auth0, Azure AD, or your own implementation. For this example, we'll assume you're using a third-party OAuth2 provider.
2. Configuring OAuth2 in .NET Core
Once your authorization server is set up, you need to configure your .NET Core application to use OAuth2 for securing your API.
Install the Required Packages
Ensure you have the necessary NuGet package:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Configure Services in Startup.cs
Next, configure the authentication services in the Startup.cs
file:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "https://YOUR_OAUTH2_AUTHORITY_URL"; // e.g., https://auth.example.com
options.Audience = "YOUR_API_AUDIENCE"; // e.g., API identifier or client ID from your OAuth2 provider
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://YOUR_OAUTH2_AUTHORITY_URL",
ValidateAudience = true,
ValidAudience = "YOUR_API_AUDIENCE",
ValidateLifetime = true
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
In this configuration:
JwtBearerDefaults.AuthenticationScheme
is used to specify that the app will authenticate using JWT tokens issued by an OAuth2 authorization server.Authority
is the URL of your OAuth2 authorization server.Audience
is the identifier of your API that clients must specify when requesting tokens.
3. Securing the Item API with OAuth2
With OAuth2 configured, you can secure your Item API by adding the [Authorize]
attribute to your controller or specific actions.
Securing the Controller
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
namespace ItemApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ItemsController : ControllerBase
{
private static List<Item> Items = new List<Item>
{
new Item { Id = 1, Name = "Item1", Description = "First item" },
new Item { Id = 2, Name = "Item2", Description = "Second item" },
};
[HttpGet]
public ActionResult<IEnumerable<Item>> GetItems()
{
return Ok(Items);
}
[HttpGet("{id}")]
public ActionResult<Item> GetItem(int id)
{
var item = Items.FirstOrDefault(i => i.Id == id);
if (item == null)
{
return NotFound();
}
return Ok(item);
}
// Other CRUD actions...
}
}
The [Authorize]
attribute ensures that only requests with valid access tokens can reach the API. If a request is made without a token or with an invalid token, the response will be a 401 Unauthorized error.
4. Testing OAuth2 Authentication
To test the OAuth2 authentication flow:
Obtain an Access Token: Use the OAuth2 authorization server to obtain an access token. This usually involves redirecting the user to the server's login page and then receiving a token in return.
Use the Access Token: Include the access token in the
Authorization
header when making API requests.
Example request with an access token:
GET /api/items HTTP/1.1
Host: localhost:5001
Authorization: Bearer YOUR_ACCESS_TOKEN
If the token is valid and the configuration is correct, the API will return the requested data. Otherwise, it will return a 401 Unauthorized error.
Conclusion
OAuth2 is a powerful and flexible protocol for securing web APIs. By following the steps outlined in this blog, you can implement OAuth2 authentication in your .NET Core applications, securing your endpoints with token-based access control.
This example demonstrates how to configure OAuth2 in a .NET Core application, secure an Item API, and handle requests with access tokens. Whether you're using a third-party authorization server or your own implementation, OAuth2 provides a robust solution for managing access to your APIs.