Next.js supports multiple authentication patterns, each designed for different use cases. But once the software knows who the user is, authorization becomes the most important factor. You have to determine this user’s permissions within the software. You can go through and write out the code, trying to think of every possible avenue you need your authenticated users to access, or you can use Cerbos.
Cerbos is a solution for handling all the use cases for your authenticated users and what they are able to access and change within your application. Everything with Cerbos is straightforward and easy to follow, allowing you to focus on other aspects of your application without going through the frustrations that come along with dealing with authorization on your own.
Let’s start by talking about what Next.js is, and why you would want to use it for your next application. It is an open-source framework that lets you build server-side rendering and static web applications using React.
Next.js also gives you a great experience with all the features like TypeScript support, smart bundling, route prefetching, and more. There is no need to configure anything to get your application running as it comes with its own configuration. There is no need for webpack, or something like it, to start using Next.js.
All you have to do after getting the initial install and app created is run
npm run dev
, and you are ready to go.
To understand authentication in Next.js, you need to first decide what you want to do. There are two main patterns of authentication in Next.js that require you to decide what you want to do.
You can use static generation to server-render a loading state which is then followed by fetching user data client-side, or you can fetch user data server-side to eliminate a flash of unauthenticated content.
There are a multitude of ways to plug authentication into your application with Next.js, and below are just a couple of examples on setting up a simple user profile and login page.
Here is an example of a user sign in using a statically generated page:
// pages/user.js
import useUser from '../lib/useUser'
import Layout from '../components/Layout'
const UserProfilePage = () => {
// Fetch the user client-side
const { user } = useUser({ redirectTo: '/login' })
// Server-render loading state
if (!user || user.isLoggedIn === false) {
return <Layout>Loading...</Layout>
}
// Once the user request finishes, show the user
return (
<Layout>
<h1>Your Profile</h1>
<pre>{JSON.stringify(user, null, 2)}</pre>
</Layout>
)
}
export default UserProfilePage
Or you could use another service like Clerk to simplify this for the profile:
import { UserProfile } from '@clerk/nextjs'
const UserProfilePage = () => <UserProfile path="/user" routing="path" />
export default UserProfilePage
And you would add this for the signup page:
import { SignUp } from '@clerk/nextjs'
const SignUpPage = () => (
<SignUp path="/sign-up" routh="path" signInUrl="/sign-in" />
)
export default SignUpPage
Whatever option you choose is up to you, and that is part of what makes Next.js an effective and simple-to-use aspect of authentication for your application.
When it comes to adding authorization, nothing is as simple as adding Cerbos. It allows for independent authorization, so there is no extra bloat from token requests. You don’t have to worry about additional workarounds either.
It also allows you to give fine grained access controls that extend the roles defined in NextJS while also giving more contextual access controls. In this way, Cerbos is a great addition for authorization.
Adding it to your application by defining access policies using human-readable YAML is a breeze. There is no need to learn a new policy language.
Start by creating a directory to hold the config file and policies:
mkdir -p cerbos-quickstart/policies
One YAML file will be labeled config.yaml
. For configuration, it
would look like this:
---
server:
httpListenAddr: ":3592"
grpcListenAddr: ":3593"
storage:
driver: "disk" # Valid values are "disk" or "git"
disk: # Only required if "driver" is "disk"
directory: /policies
watchForChanges: true
The other YAML file will be labeled contact.yaml
. This sets what
your users will be able to do:
---
apiVersion: api.cerbos.dev/v1
resourcePolicy:
version: default
resource: contact
rules:
- actions: ["read", "create"]
effect: EFFECT_ALLOW
roles:
- admin
- user
- actions: ["update", "delete"]
effect: EFFECT_ALLOW
roles:
- admin
- actions: ["update", "delete"]
effect: EFFECT_ALLOW
roles:
- user
condition:
match:
expr: request.resource.attr.owner == request.principal.id
After you have set up your config and policies, you will navigate and set up your API folder to add Cerbos to your application. This is what enables access decisions in milliseconds.
First, you need to install the client library for interacting with the Cerbos policy decision point over gRPC from server-side Node.js applications, and it would like this:
$ npm install @cerbos/grpc
or
$ yarn add @cerbos/grpc
For this API example, we have named our file getResources.js
, and
the code within in it would look like this:
import { requireSession, users } from "@clerk/nextjs/api";
import { GRPC as Cerbos } from "@cerbos/grpc";
const cerbos = new Cerbos(
"demo-express-clerk-cerbos-pdp-qh5dbmiiva-uk.a.run.app",
{
tls: true,
}
);
export default requireSession(async (req, res) => {
const user = await users.getUser(req.session.userId);
const roles = user.publicMetadata.role
? [user.publicMetadata.role]
: ["user"];
const cerbosPayload = {
principal: {
id: req.session.userId,
roles, //roles from Clerk profile
attributes: {
email: user.email,
},
},
resources: [
{
resource: {
kind: "contact",
id: "1",
attributes: {
owner: req.session.userId,
lastUpdated: new Date(2020, 10, 10),
},
},
actions: ["read", "create", "update", "delete"],
},
{
resource: {
kind: "contact",
id: "2",
attributes: {
owner: "test2",
lastUpdated: new Date(2020, 10, 10),
},
},
actions: ["read", "create", "update", "delete"],
},
],
};
console.log(cerbosPayload);
const result = await cerbos.checkResources(cerbosPayload);
res.json(result.results);
});
As you can see, setting up authorization doesn’t have to be a large endeavor, and shouldn’t take a team long to implement into an application, saving time and money on a project.
Integrating Cerbos with NextJS will provide a variety of benefits related to security and authorization, including:
By integrating Cerbos with NextJS you will have the ability to define access control policies for your NextJS applications, specifying which user can perform which actions when and in what context.
Integrating Cerbos with NextJS RBAC typically involves configuring your NextJS application to make NextJS authorization requests to Cerbos. Then configuring the app to process the responses from Cerbos in the desired manner.
Next.js is a quickly growing framework used with React, and Cerbos is an open-source, decoupled access control for your application. With any new application that you plan on making, it should be secure. Authentication allows users to be secure with login information and who they are. Authorization is an important part of any secure application by giving users roles and permissions within the application.
We have looked at why Next.js may be the framework you choose to use for your next application, and we also looked at an example of how it handles authentication. Finally, we explored some of the benefits of integrating Cerbos with NextJS.
Cerbos comes in to make authorizing users a simple task that can save time and money during application development. Cerbos makes it simple to define access policies using human-readable YAML because there’s no need to learn a new policy language, and accessing the API takes milliseconds.
Integrating Cerbos with NextJS should be the next thing you should try in your application for powerful authorization!
Book a free Policy Workshop to discuss your requirements and get your first policy written by the Cerbos team