Setting Up Auth0 with Next.js: User & Admin Roles
Why use Auth0 with Next.js?
In today’s digital landscape, user authentication and authorization are critical components of any web application. Auth0 is a flexible, drop-in solution that simplifies adding authentication and authorization services to your applications with minimal setup. It supports various methods, including social login, multi-factor authentication, and enterprise federation, making it highly versatile for web apps.
With Next.js, you get the added benefit of server-side rendering and static site generation. Pairing Auth0 with Next.js allows you to create a secure, scalable, and modern web application that handles user login and role-based access control (RBAC) efficiently.
- Auth0 Documentation : https://auth0.com/docs/get-started
- NextJs Documentation : https://nextjs.org/docs
What This Blog Will Cover
In this blog, we’ll walk you through setting up Auth0 with Next.js, focusing on creating default user and admin roles to manage access control effectively. We’ll cover the following topics:
- Setting Up Auth0 with Next.js: Learn how to configure your Next.js application to use Auth0 for authentication.
- Creating and Managing Roles in Auth0: Understand how to create user roles like “Admin” and “User” and assign them within the Auth0 dashboard.
- Integrating Authentication and Authorization in Next.js: Discover how to implement role-based access control (RBAC) to protect routes and manage user access.
- Testing and Debugging: Learn how to test your authentication setup to ensure that everything works as expected.
By the end of this guide, you will have a fully functional authentication system integrated into your Next.js application, with both user and admin roles configured for secure and efficient access management.
GitHub Link : https://github.com/chamidu044/test-auth0.git
1. Setting Up Auth0 with Next.js
Step 1: Create Next.js Project
Firstly, create a Next.js project using the below command on your terminal.
npx create-next-app@latest
What is your project named? test-auth0
Would you like to use TypeScript? (Yes)
Would you like to use ESLint? (Yes)
Would you like to use Tailwind CSS? (Yes)
Would you like your code inside a `src/` directory? (No)
Would you like to use App Router? (recommended) (Yes)
Would you like to customize the import alias (`@/*` by default)? (No)
Step 2: Install Auth0 SDK
Install the Auth0 SDK by running the following command in your Next.js project directory:
npm install @auth0/nextjs-auth0
Step 3: Set Up API Routes
Then on your app directory create a route.ts
file within the below folder structure as api/auth/[auth0]/ . (Refer github repository for file structure)
Here’s the code for route.ts
to add login, logout, and callback routes:
# sets up the necessary routes for Auth0 to handle login/logout
import { handleAuth } from '@auth0/nextjs-auth0';
export const GET = handleAuth();
Step 4: Configure Auth0 Dashboard
In the Auth0 dashboard:
- Create a Regular Web Application and select Next.js as the base.
- Under Settings > Application URIs,
- Update the Allowed Callback URLs to:
http://localhost:3002/api/auth/callback
(changelocalhost:3002
if needed). - Update the Allowed Logout URLs to:
http://localhost:3002/, http://localhost:3002/api/auth/logout
Step 5: Set Up Environment Variables
Create a .env.local
file in the root directory of your project. Alternatively, you can add these configurations to the code, but using an env is recommended.
Install thedotenv
package to support reading from the env:
yarn add dotenv
Paste the following credentials, which you can obtain from your Auth0 dashboard:
# generate a auth0 secret by terminal.
# Use the below command to generate a random string value
# node -e "console. log (crypto. randomBytes (32) . toString ('hex'))"
AUTH0_SECRET=long string value
# The base url of your application
AUTH0_BASE_URL='http://localhost:3002'
# The url of your Auth0 tenant domain
AUTH0_ISSUER_BASE_URL='https://<YOUR_AUTH0_DOMAIN>.auth0.com'
# Your Auth0 application's Client ID
AUTH0_CLIENT_ID='<YOUR_AUTH0_CLIENT_ID>'
# Your Auth0 application's Client Secret
AUTH0_CLIENT_SECRET='<YOUR_AUTH0_CLIENT_SECRET>'
Step 6: Implement Auth0 Login in Next.js
Update app/page.tsx
to direct users to the Auth0 login page. After login, users will be redirected to /dashboard
:
"use client";
import React from 'react';
import Link from 'next/link';
import { useUser } from '@auth0/nextjs-auth0/client';
const LoginSignup: React.FC = () => {
const { user, error, isLoading } = useUser();
return (
<div className="flex flex-col items-center justify-center h-screen bg-gray-100">
<h1 className="text-4xl font-bold mb-8 text-black">Welcome to the Platform</h1>
<div className="space-x-4">
<Link href="/api/auth/login?returnTo=/dashboard&prompt=login"
className="px-6 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition">
Login
</Link>
</div>
</div>
);
};
export default LoginSignup;
Step 7: Wrap the App with <UserProvider>
To manage authentication across your app, wrap the entire app in the <UserProvider>
component by updating layout.tsx
:
2. Creating and Managing Roles in Auth0
Roles help control access to specific routes or features in your app. Auth0 lets you create and manage these roles in the dashboard.
Step 1: Create Roles in Auth0
In the Auth0 Dashboard, navigate to User Management > Roles to create roles like “User” and “Admin.” You can assign these roles to users manually in the dashboard.
Step 2: Assign Default Role Using Auth0 Actions
To automatically assign a default role to users upon login, we’ll use Auth0 Actions. This is useful for managing RBAC in your app.
If we are integrating role-based access control (RBAC) we have to develop a logic to assign Employee (default role) to users when logging in and we can manually assign Admin role from auth0 dashboard.
Step 2.1: Create a Machine-to-Machine (M2M) Application
First, you’ll need to create a Machine-to-Machine (M2M) application in Auth0 to allow your Post-Login Action to communicate with the Auth0 Management API for assigning roles.
- Go to Applications > Create Application, and select Machine-to-Machine (M2M).
- In the Applications > APIs > API Permissions section, enable access to the Auth0 Management API with the following scopes:
update:users
read:users
read:roles
update:roles
If you are using the System API then it is already enabled with permissions. In your M2M Application give access to auth0 management API for access it.
After setting up the M2M application, take note of the Client ID
, Client Secret
, and your Auth0 domain. You'll need these values in the next step.
Step 2.2: Set Up Post-Login Action
- Go to Actions > Library > Create Action and choose Build from Scratch and select below options and create.
- Paste the following code into the action editor, replacing
YOUR_DEFAULT_USER_ID
with your role ID:
/**
* Handler that will be called during the execution of a PostLogin Flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
// Check if the user has a role assigned
if (event.authorization && event.authorization.roles && event.authorization.roles.length > 0) {
return;
}
// Create management API client instance
const ManagementClient = require("auth0").ManagementClient;
const management = new ManagementClient({
domain: event.secrets.DOMAIN,
clientId: event.secrets.CLIENT_ID,
clientSecret: event.secrets.CLIENT_SECRET,
});
const params = { id : event.user.user_id };
const data = { "roles" : ["YOUR_DEFAULT_USER_ID"] };
try {
await management.users.assignRoles(params, data);
} catch (e) {
console.log(e);
}
};
- Set up the required secrets (
DOMAIN
,CLIENT_ID
,CLIENT_SECRET
) in the Secrets tab, using the values from your M2M application. - Install auth0 with
auth0@latest
command in Dependancies Tab.
- Finally, deploy the action and enable it in your Post-Login Flow by going to Actions > Flows > Login and adding the custom action.
3. Integrating Role-Based Access Control (RBAC) in Next.js
Once roles are set up, you’ll need to integrate RBAC in Next.js to restrict routes or content based on user roles.
Step 1: Create API Route for Role Management
Install axios depending on your package manager:
npm install axios
In app/api/roles/route.ts
, handle requests to fetch user roles:
import { NextRequest, NextResponse } from 'next/server';
import axios from 'axios';
// step 01
const getAuth0Token = async () => {
const response = await axios.post(`https://<YOUR_AUTH0_DOMAIN>.auth0.com/oauth/token`, {
client_id: process.env.NEXT_PUBLIC_AUTH0_M2M_CLIENT_ID,
client_secret: process.env.NEXT_PUBLIC_AUTH0_M2M_CLIENT_SECRET,
audience: 'https://<YOUR_AUTH0_DOMAIN>.auth0.com/api/v2/',
grant_type: 'client_credentials',
});
return response.data.access_token;
};
// step 02
const getUserRolesFromAuth0 = async (userId: string, token: string) => {
const response = await axios.get(`https://<YOUR_AUTH0_DOMAIN>.auth0.com/api/v2/users/${userId}/roles`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return response.data;
};
// step 03
export async function POST(req: NextRequest) {
try {
const { userId } = await req.json();
const token = await getAuth0Token();
const roles = await getUserRolesFromAuth0(userId, token);
return NextResponse.json({ roles });
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch user roles' }, { status: 500 });
}
}
.env file configuration with M2M Auth0 credentials as below
#M2M AUTH0
NEXT_PUBLIC_AUTH0_M2M_CLIENT_ID='YOUR_CLIENT_ID'
NEXT_PUBLIC_AUTH0_M2M_CLIENT_SECRET='YOUR_CLIENT_SECRET'
- Step 01 : Fetching an Auth0 Access Token
In the RBAC setup, we need to communicate with the Auth0 Management API to fetch user roles. This requires an access token, which can be obtained by authenticating through the Auth0 Machine-to-Machine (M2M) application. This sends a request to the Auth0 OAuth token endpoint, exchanging the machine-to-machine client ID and secret for an access token.
- Step 02 : Fetching User Roles from Auth0
Once the token is available, we can use it to query the Auth0 API to get the roles assigned to a specific user. This makes a GET request to the Auth0 Management API to retrieve the roles assigned to the user with the specified userId
- Step 03 : API Route to Handle Role Requests
Next, we create an API route in Next.js that handles requests to fetch user roles. This API route interacts with the functions above.
On the client side, fetch user roles when a user logs in. Create a dashboard/page.tsx
component:
"use client";
import React, { useEffect, useState } from 'react';
import { useUser } from '@auth0/nextjs-auth0/client';
import axios from 'axios';
const Dashboard: React.FC = () => {
const { user, error, isLoading } = useUser();
const [roles, setRoles] = useState<string[]>([]);
// Step 04
useEffect(() => {
const fetchUserRoles = async () => {
if (user) {
try {
const response = await axios.post('/api/roles', { userId: user.sub });
response.data.roles.map((role: any) => role.id);
setRoles(response.data.roles.map((role: any) => role.name));
} catch (err) {
console.error('Error fetching user roles:', err);
}
}
};
fetchUserRoles();
}, [user]);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>{error.message}</div>;
const logout = () => {
const logoutUrl = "http://localhost:3002/api/auth/logout";
window.location.href = logoutUrl;
};
// step 05
return (
<div className="h-screen flex flex-col items-center justify-center bg-gray-100 text-black">
<div className="bg-white p-8 rounded shadow-md w-full max-w-md text-center">
{user ? (
<>
<h1 className="text-2xl font-bold">Welcome, {user.name}!</h1>
<p className="mt-4">Here is your Auth0 user data:</p>
<table className="bg-gray-100 p-4 rounded mt-4 text-left w-full">
<tbody>
<tr>
<td className="font-bold">Name:</td>
<td>{user.name}</td>
</tr>
<tr>
<td className="font-bold">Email:</td>
<td>{user.email}</td>
</tr>
<tr>
<td className="font-bold">Nickname:</td>
<td>{user.nickname}</td>
</tr>
<tr>
<td className="font-bold">Picture:</td>
<td><img src={user.picture ?? ''} alt="User Picture" className="rounded-full w-16 h-16" /></td>
</tr>
<tr>
<td className="font-bold">Auth0 ID:</td>
<td>{user.sub}</td>
</tr>
<tr>
<td className="font-bold">Roles:</td>
<td>{roles.length > 0 ? roles.join(', ') : 'No roles assigned'}</td>
</tr>
</tbody>
</table>
{roles.includes('Admin') && (
<button className="mt-6 bg-blue-500 text-white rounded p-2">Admin Settings</button>
)}
<button onClick={logout} className="mt-6 px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600">
Logout
</button>
</>
) : (
<p>Please log in to view your dashboard.</p>
)}
</div>
</div>
);
};
export default Dashboard;
- Step 04 : Fetching Roles on the Client-Side
Create the page.tsx file in app > dashboard folder path to create a route as /dashboard from your app directory.
On the client side, we can use React’s useEffect
hook to fetch user roles when a user logs in. This ensures that the role data is available as soon as the user accesses the application.
This runs when the user
object is available (after the user logs in). It sends the userId
to the API route we created, retrieves the user roles, and stores them in the component's state (roles
).
- Step 05 : Displaying User Information and Roles
Once the roles have been fetched, we display the user’s information, including their name, auth0 ID and assigned roles, on the dashboard.
4. Testing and Debugging
- Create a Test User: Go to the Auth0 Dashboard and create a test user, or use the signup option from auth0 login from web application created.
- Login as the Test User: Log in to your application using this test account. Upon successful login, your Auth0 Post-Login action should assign the default role to the user.
- Go to the Auth0 Dashboard.
- Navigate to User Management > Users.
- Click on the user and check the Roles tab. You should see the assigned role (e.g., “Employee”).
- Create another user from auth0 dashboard and assign the role as “Admin”.
- Try login from these 2 accounts and check how the user details are shown.
Troubleshooting Tips:
- Incorrect Callback URL: Double-check the callback URL in your Auth0 dashboard if you’re not being redirected correctly.
- Roles Not Assigned Automatically: Verify that your Auth0 Post-Login Action is correctly deployed and that the role ID is correct.
- Environment Variables: Ensure all environment variables are set up properly in your
.env.local
file.
Below is the folder structure and the github link to my repository for further clarification on setting up the NextJs with Auth0 Authorization.
GitHub Link : https://github.com/chamidu044/test-auth0.git
Useful Links :
- Auth0 Documentation : https://auth0.com/docs/get-started
- NextJs Documentation : https://nextjs.org/docs
Conclusion
In this guide, we’ve walked through integrating Auth0 with Next.js to set up user authentication and role-based access control. You’ve learned how to create and manage user roles in Auth0, implement RBAC in your Next.js app, and test the functionality.
With this setup, you can now manage user roles dynamically and secure your app’s routes and features based on roles like User and Admin. From here, consider expanding the system by adding additional roles, integrating multi-factor authentication (MFA), or exploring more advanced actions with Auth0.