This blog was originally published on development process. This helps to ensure that only authenticated users can access the protected resources of your application and that each user can access only the resources they are allowed to access.
In this guide, you'll learn how to implement Next.js 14 authentication and role-based access control (RBAC) using the .
RBAC in this tutorial
This tutorial uses role-based access control (RBAC) to manage who can do what in the blogging app:
Editor role: Can create and edit posts
Admin role: Can view and publish posts
Instead of assigning permissions to individual users, you'll assign them to roles. Then you’ll assign users to roles. This makes managing permissions scalable as your app grows. To learn more about RBAC concepts, benefits, and implementation strategies, see:
This tutorial uses SSR with App Router, Next.js 14's file-system-based routing solution, to implement authentication that verifies on the server before rendering.
Setting up Descope for Next.js 14 authentication
Descope simplifies adding Next.js 14 authentication and authorization by offering an intuitive SDK and visual flows to build authentication screens.
. This feature abstracts away the implementation details of authentication methods, session management, and error handling, allowing you to focus on building the core features of your application rather than handling these complexities.
Using Descope eliminates the need to write authentication and authorization logic from scratch, saving valuable development time and reducing the risk of security vulnerabilities. Descope's infrastructure ensures your application's authentication and authorization mechanisms are secure, scalable, and easy to maintain.
The following sections explain how you can implement these features in a Next.js application using Descope. To follow along, you need the following:
installed- , create a new project with the name
descope-nextjs-auth-rbac:
Select
Magic LinkforWhich authentication methods do you want to use?and then clickNext:
On the next page, you can view the flows generated for your project. Click
Nextto generate these flows:
Next, you need to obtain a management key. Select
Companyfrom the sidebar, select theManagement Keystab on theCompanypage, and click the+ Management Keybutton to create a new management key. Provide the key name and, underProject Assignment, selectUse this management key for all the projects in the company. Click theGenerate Keybutton and copy the value of your key:
for the models defined in the
prisma/schema.prismafile:
CODEnpx prisma migrate dev --name init
shell
Run the app with the command
npm run devand navigate tohttp://localhost:3000/on your web browser. You should see a dashboard where the posts are displayed. At the moment, no posts are available:
At this stage, the template is ready, but don’t create any posts until you have implemented authentication and authorization.
Adding authentication to Next.js 14
This section walks you through implementing authentication in your Next.js 14 application using Descope. You'll use code examples and screenshots to guide each step.
Key steps
- Install the Descope Next.js SDK
- Wrap your app with Descope authentication
- Configure the “sign up or in” function
- Protect routes with authentication middleware
- Test the authentication flow
To get started, execute the following command in the terminal to install the
Open the
app/sign-in/page.jsfile and replace the existing code with the following:
CODE"use client";
import { Descope } from "@descope/nextjs-sdk";
import axios from "axios";
import { useRouter } from "next/navigation";
export default function Page() {
const router = useRouter();
// Register user or redirect to home
const handleEvent = async (event) => {
try {
if (event.detail.firstSeen !== true) {
return router.replace("/");
}
// Register the user
const { data } = await axios.post("/api/register", {
descopeUserId: event.detail.user.userId,
email: event.detail.user.email,
name: event.detail.user.name,
});
if (data.error) {
alert("Something went wrong");
} else {
return router.replace("/");
}
} catch (error) {
console.log(error);
}
};
return (
<Descope
flowId="sign-up-or-in"
onSuccess={(e) => handleEvent(e)}
onError={(e) => alert("Something went wrong. Please try again.")}
/>
);
}
javascript
In the preceding code, once the user signs up or in successfully, the event data returned from this component is passed to the
handleEventfunction.
This function checks if the user is new by examining
event.details.firstSeen. If the user is not new, they are redirected to the home screen. Otherwise, it sends a POST request to the/api/registerendpoint with the user’s details to register the user. If the registration is successful, the user is redirected to the home page; otherwise, an error message is displayed.
The
/api/registerendpoint is defined in theapp/api/register/route.jsfiles, and it adds the user to the local database.
You also need to set up a middleware to enforce authentication for all the pages in this application. Create a file named
middleware.jsin the project root folder and add the following code:
CODEimport { authMiddleware } from "@descope/nextjs-sdk/server";
export default authMiddleware({
projectId: process.env.DESCOPE_PROJECT_ID,
redirectUrl: process.env.SIGN_IN_ROUTE,
});
export const config = {
matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
};
shell
This code uses the
authMiddlewarefunction provided by the Descope Next.js SDK to protect all routes and redirect unauthenticated users to the sign-in page.
Update the
.envfile with the following:
CODEDESCOPE_PROJECT_ID=<YOUR-PROJECT-ID>
DESCOPE_MANAGEMENT_KEY=<YOUR-MANAGEMENT-KEY>
SIGN_IN_ROUTE="/sign-in"
javascript
Make sure to replace the placeholder values with the values you obtained earlier.
The authentication for your Next.js application is now complete.
Before you test it, open the
app/write/page.jsfile. In this file, notice that thesavePostfunction requires the Descope user ID. You can retrieve this using the hooks provided by the Next.js SDK.
Add the following import statement to the file:
CODEimport { useUser } from "@descope/nextjs-sdk/client";
javascript
Add the following statement that retrieves the user just before the
savePostfunction:
CODEconst { user } = useUser();
javascript
You can now test the authentication flow.
On your browser, navigate to
http://localhost:3000. You are redirected tohttp://localhost:3000/sign-insince you have not signed in. It should look like this:
This confirms that the authentication is working as expected.
Adding authorization to Next.js 14
Currently, anyone can log in to the application, create posts, submit them for approval, and approve the posts. For this example, you want to specify that editors can write posts and then submit them for approval, and admins can publish the posts.
Key steps
- Create roles and assign permissions in Descope
- Control UI visibility based on user roles
- Validate roles in API routes
- Configure session tokens for authorization
- Test role-based permissions
Before you implement this functionality, click the
Start Writingbutton and create a few posts to test the application with:
Repeat the process to create a role for the admin. Provide “admin” as the role and “Can toggle a post’s published status” as the description.
Assign the “editor” role to the user who is logged in to the application. In the
Descope Console, selectUsersfrom the sidebar to edit the user details:
Open the
app/page.jsfile and add the following import statement:
CODEimport { useUser } from "@descope/nextjs-sdk/client";
javascript
Add the following code before the
fetchPostsfunction.
CODEconst { user } = useUser();
javascript
This hook allows you to retrieve the user’s details.
Locate the following lines of code in the same file:
CODE<Link
href={"/write"}
className="px-4 py-1 border rounded-lg bg-black text-white"
>
Start Writing
</Link>
javascript
Replace it with the following to display only the
Start Writingbutton to editors:
CODE{
user?.roleNames?.includes("editor") && (
<Link
href={"/write"}
className="px-4 py-1 border rounded-lg bg-black text-white"
>
Start Writing
</Link>
)
}
javascript
Open the
app/posts/[postId]/page.jsfile and add the following lines of code in their respective locations (indicated by the comments):
CODEimport { useUser } from "@descope/nextjs-sdk/client"; // After the import statement
const { user } = useUser(); // Before the return statement
javascript
Locate the following lines of code:
CODE<Button
variant="default"
className="px-6 mt-6"
onClick={() => togglePublishedStatus()}
>
{post.published ? "Unpublish" : "Publish"}
</Button>
javascript
Replace it with the following to specify that only admins can publish/unpublish a post:
CODE{
user?.roleNames?.includes("admin") && (
<Button
variant="default"
className="px-6 mt-6"
onClick={() => togglePublishedStatus()}
>
{post.published ? "Unpublish" : "Publish"}
</Button>
)
}
javascript
For additional security, you also validate these roles in the API router handlers. In the lib folder, create a new file named
descope.jsand add the following code:
CODEimport { createSdk } from "@descope/nextjs-sdk/server";
export const descopeSdk = createSdk({
projectId: process.env.DESCOPE_PROJECT_ID,
managementKey: process.env.DESCOPE_MANAGEMENT_KEY,
});
javascript
This code initializes a Descope client instance and exports it for use in other parts of the application.
Open the
app/api/posts/create/route.jsfile and add the following code just afterconst data = await request.json():
CODE// Make sure the user has the editor role
const userRoles = descopeSdk.getJwtRoles(data.sessionToken);
if (!userRoles?.includes("editor")) {
throw new Error("User is not an editor");
}
javascript
This code ensures that the user has the editor role. If not, it throws an error.
Remember to add the following import statement:
CODEimport { descopeSdk } from "@/lib/descope";
javascript
Open the
app/api/posts/toggleStatus/route.jsfile and add the following code just afterconst data = await request.json()to throw an error if the user making the request does not have the admin role:
CODE// Make sure the user has the admin role
const userRoles = descopeSdk.getJwtRoles(data.sessionToken);
if (!userRoles?.includes("admin")) {
throw new Error("User is not an admin");
}
javascript
Remember to add the following
importstatement:
CODEimport { descopeSdk } from "@/lib/descope";
javascript
With the route handlers verifying the user roles, you need to make sure that the session token is passed in the request body. Start by opening the
app/write/page.jsfile and retrieving the session token using theuseSessionhook:
CODEconst { sessionToken } = useSession();
javascript
Make sure the
useSessionhook is imported into the file:
CODEimport { useSession, useUser } from "@descope/nextjs-sdk/client";
javascript
Add the retrieved session token to the body of the POST request in the savePost function:
CODEconst { data } = await axios.post("/api/posts/create", {
title,
content,
descopeUserId: user?.userId,
sessionToken,
});
javascript
Open the
app/posts/[postId]/page.jsfile and retrieve the session token using theuseSessionhook:
CODEconst { sessionToken } = useSession();
javascript
Make sure the hook is imported into the file:
CODEimport { useSession, useUser } from "@descope/nextjs-sdk/client";
javascript
Replace the
togglePublishedStatusfunction with the following code that ensures that the session token is passed to the route handlers:
CODEconst togglePublishedStatus = async () => {
try {
const { data } = await axios.put("/api/posts/toggleStatus", {
postId: params.postId,
sessionToken,
});
setPost(data.data);
} catch (error) {
alert("Something went wrong");
console.log(error);
}
};
Now, all the authorization checks are complete. You can test to see if everything is working as expected.
Navigate to
http://localhost:3000/sign-inand log in to the application. Since you assigned the editor role to the user, you can see theStart Writingbutton:
Now, go back to the
Descope Consoleand assign the user theadminrole.
Go back to the application and refresh the page. Since the user now has the admin role, they can see the button to
Publish/Unpublisha post:
on GitHub.
Next steps for Next.js 14 authentication
Your authentication system is production-ready. You can extend it by adding powerful for production applications. Use no-code workflows to add authentication methods, configure authorization rules, and manage users at scale, so you can focus on your application's core features instead of authentication infrastructure.
Start building with a .
↗ Original-Artikel auf dev.to lesenVollständiger Original-BerichtAusführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
SOCIAL SHARE CARD GENERATOR