Building a Secure Next.js Frontend and .NET 8 API with Auth0: Implementing Resource-Based and Role-Based Authorization

Building a Secure Next.js Frontend and .NET 8 API with Auth0: Implementing Resource-Based and Role-Based Authorization

Overview

When building modern web applications, securing your backend API and ensuring proper authorization are critical. In this post, we’ll guide you through integrating Auth0 with a Next.js frontend and a .NET 8 API to implement resource-based and role-based authorization.

What You’ll Learn:

  • How to integrate Auth0 with Next.js for authentication.
  • How to configure .NET 8 API for JWT-based authentication with Auth0.
  • How to implement resource-based authorization and role-based authorization in the .NET API.

Why Auth0?

Auth0 is a robust platform that makes it easy to implement authentication and authorization across your apps. By offloading authentication to Auth0, you can focus on building your app while using secure and scalable authentication services. Auth0 also provides built-in support for JWT tokens, user roles, and resource-based authorization, making it a great fit for modern, secure web apps.


Step 1: Setting Up Auth0

1.1. Create a New Auth0 Application

  1. Log in to Auth0 and navigate to the Dashboard.
  2. Under Applications, create a new Single Page Web Application for your Next.js frontend.
  3. Go to Settings and configure:
  • Allowed Callback URLs: http://localhost:3000/callback
  • Allowed Logout URLs: http://localhost:3000
  • Allowed Web Origins: http://localhost:3000

1.2. Create an Auth0 API

  1. Navigate to the APIs section and create a new API for your .NET backend.
  2. Set the Identifier to something like https://my-api.com.
  3. Under Settings, configure your signing algorithm to RS256.

Step 2: Setting Up the .NET 8 API

2.1. Create a New .NET 8 API Project

If you don’t have a .NET 8 project, create one:

dotnet new webapi -n Auth0ResourceBasedApi
cd Auth0ResourceBasedApi

2.2. Add JWT Bearer Authentication to the .NET 8 API

In Program.cs, configure your API to validate tokens from Auth0:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
// Configure JWT Bearer authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = $"https://{builder.Configuration["Auth0:Domain"]}/";
options.Audience = builder.Configuration["Auth0:Audience"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = $"https://{builder.Configuration["Auth0:Domain"]}/",
ValidateAudience = true,
ValidAudience = builder.Configuration["Auth0:Audience"],
ValidateLifetime = true
};
});
builder.Services.AddAuthorization();
builder.Services.AddControllers();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

2.3. Configure the appsettings.json

In the appsettings.json file, add your Auth0 domain and API identifier:

{
"Auth0": {
"Domain": "your-auth0-domain.us.auth0.com",
"Audience": "https://my-api.com"
}
}

Step 3: Role-Based Authorization in .NET 8 API

Role-based authorization allows you to restrict API access based on user roles assigned in Auth0.

3.1. Create a Role in Auth0

  1. Go to User Management -> Roles in Auth0.
  2. Create roles such as Admin or User, and assign these roles to users in your application.

3.2. Add Role-Based Authorization to Your API

In your .NET 8 API, add role-based authorization to your controller actions using the [Authorize] attribute with a specified role.

For example, protecting a specific endpoint to only allow users with the Admin role:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
// Protect this endpoint for users with the "Admin" role
[HttpGet("{id}")]
[Authorize(Roles = "Admin")]
public IActionResult GetDocument(int id)
{
return Ok(new { id, content = "This is a protected document for Admins." });
}
}

Step 4: Resource-Based Authorization in .NET 8 API

Resource-based authorization ensures that only resource owners can access or modify specific resources.

4.1. Implement a Custom Authorization Handler

Create a custom AuthorizationHandler to handle resource-based checks:

using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
public class ResourceOwnerRequirement : IAuthorizationRequirement { }
public class ResourceOwnerAuthorizationHandler : AuthorizationHandler<ResourceOwnerRequirement, Resource>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 
ResourceOwnerRequirement requirement, 
Resource resource)
{
var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userId == resource.OwnerId)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class Resource
{
public string Id { get; set; }
public string OwnerId { get; set; }
}

4.2. Apply Resource-Based Authorization in the Controller

Apply the custom authorization handler in the controller to protect specific resources:

[HttpGet("{id}")]
[Authorize(Policy = "ResourceOwner")]
public IActionResult GetDocument(string id)
{
var document = Documents.FirstOrDefault(d => d.Id == id);
if (document == null)
{
return NotFound();
}
var resource = new Resource { Id = document.Id, OwnerId = document.OwnerId };
return Ok(resource);
}

Step 5: Set Up the Next.js Frontend

5.1. Install the Auth0 SDK in Next.js

First, create your Next.js project and install the Auth0 SDK:

npx create-next-app@latest my-auth0-app
cd my-auth0-app
npm install @auth0/auth0-react

5.2. Configure Auth0 in layout.tsx

To handle authentication, wrap your entire app with the Auth0Provider component:

"use client";
import { Auth0Provider } from '@auth0/auth0-react';
import { useRouter } from 'next/navigation';
import { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) {
const router = useRouter();
const onRedirectCallback = (appState: any) => {
router.push(appState?.returnTo || '/');
};
return (
<Auth0Provider
domain="your-auth0-domain.us.auth0.com"
clientId="your-auth0-client-id"
authorizationParams={{
redirect_uri: window.location.origin,
audience: "https://my-api.com",
}}
onRedirectCallback={onRedirectCallback}
>
{children}
</Auth0Provider>
);
}

5.3. Make Authenticated API Requests

Use getAccessTokenSilently from the Auth0 SDK to fetch a token and include it in your requests to the .NET 8 API.

Example for fetching protected resources:

"use client";
import { useAuth0 } from '@auth0/auth0-react';
import { useEffect, useState } from 'react';
export default function ProtectedApiCall() {
const { getAccessTokenSilently } = useAuth0();
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const token = await getAccessTokenSilently();
const response = await fetch('https://localhost:5001/api/documents/1', {
headers: {
Authorization: `Bearer ${token}`,
},
});
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, [getAccessTokenSilently]);
return (
<div>
<h1>Protected API Call</h1>
{data ? <pre>{JSON.stringify(data, null, 2)}</pre> : 'Loading...'}
</div>
);
}

Conclusion

In this post, we’ve built a secure Next.js frontend and .NET 8 API using Auth0 for authentication and both resource-based and role-based authorization. This setup ensures that:

  • Role-based authorization limits access to certain routes based on user roles.
  • Resource-based authorization enforces ownership over specific resources in your API.

By leveraging Auth0, Next.js, and .NET 8, you

can build secure applications with ease.

References:


This setup should give you a solid foundation for securely handling authentication and authorization in your full-stack applications. Let me know if you need more details!

Leave a Reply

Your email address will not be published. Required fields are marked *