Security-charging Your NextJS 14 App with Userfront Authentication

Whether you're new to authentication in NextJS or looking to migrate to a modern identity and authentication management system, this guide provides you with the knowledge to build a robust, secure authentication system using Userfront in your NextJS 14 application.

December 11, 2024
5 Min Read

As we build increasingly complex applications with NextJS 14, it's crucial to implement authentication and authorization correctly. Developers know that Identity Management and Authentication (IAM) is a revenue driver. Users need easy security they can place confidence in, and companies need organizational architectures and compliance.

Are you looking for a modern, easy-to-implement IAM that supports NextJS 14 application design and best practices? This article guides you through integrating Userfront authentication into your NextJS 14 app, focusing on security best practices.

We'll start by covering the basics of Userfront integration, but our main goal is to dive deep into the implementation of a secure, production-ready authentication system. We explore:

  1. Client-side authentication flows using Userfront's components
  2. Secure routing and protected layouts in NextJS 14
  3. Implementing server-side verification for sensitive data access, ensuring authorization checks are performed close to the data source

Throughout, we emphasize the separation of concerns between client and server, the importance of server-side validation, and the proper handling of JWTs.

Let's begin by setting up Userfront in a NextJS 14 project, and then we'll progressively build out our secure authentication infrastructure.

Get started with Userfront for NextJS 14

The Userfront Next SDK integrates seamlessly with NextJS, allowing developers to implement secure authentication quickly and efficiently. Userfront provides a comprehensive solution for adding authentication to your NextJS 14 application. It offers:

  • A generous free tier with a user data source prepopulated
  • Plug-and-play components
  • A range of sign-on methods from emails to SSO
  • Custom JWTs for the fields you want to capture
  • Multi-tenancy

Here are four essential resources to get you started with Userfront in your NextJS 14 project:

  1. @userfront/next package on npm provides a set of components and hooks that make it easy to add authentication to your Next.js app.
  2. Quick Start guide walks you through the basics of setting up Userfront in your project, including:
    • Installing the Userfront Next.js library
    • Adding the Userfront provider to your layout
    • Creating login, signup, and dashboard pages
  3. Userfront Next.js Guide is a more in-depth look at integrating Userfront with Next.js. This guide covers:
    • Installation and setup
    • Using the UserfrontProvider
    • Client-side components and hooks
    • Server-side methods and authentication
  4. Userfront NextJS 14 example on GitHub is a fully functional authentication setup using Userfront in a NextJS 14 application.

Build on the Userfront NextJS 14 example

Now that we've covered the basics, let's dive into some best practices for using Userfront with NextJS 14. We'll focus on understanding NextJS 14's design principles and how to keep sensitive data secure to ensure that:

  • Only requests with valid JWTs can access the protected data
  • The server verifies the user's identity before returning any sensitive information
  • The client-side component (UserDataComponent) can't access this data without a valid token

Set up the project

First, make sure you have a Next.js 14 project set up with Userfront installed. If you haven't done this yet, you can grab the example from GitHub by downloading the folder. For example, you can go to download-directory and enter the NextJS project: https://github.com/userfront/examples/tree/main/next-14.

Open the project up and install it with:

Run the example:

Next, we’ll add a header that changes based on the user login state, a secured router, and a dashboard page that fetches user data if the JWT is verified.

Create a Header component

Let's start by creating a header component that changes based on the user's authentication status:

This header component uses the useUserfront hook to determine if the user is authenticated and displays appropriate navigation links.

Then, we’ll update the app layout to include that header. Replace the contents of app/layout.tsx with the following code:

Secure routes with layout

Next, let's create a secure layout that protects our dashboard and other sensitive pages. Secure layouts provide a client-side redirect for unauthenticated users, but remember that true security should be implemented server-side.

This layout ensures that only authenticated users can access the pages within the (secure) folder.

Fetch Userfront data as server-side call

To fetch data on the server, we’ll can the UserfrontClient along with the Userfront Admin API key and Tenant ID, which are found in the dashboard.

We’ll also add Cloudinary as an image in the root next.config.mjs file:

Now if you run the app, login, and go to the Dashboard, the link Server Example with Data Fetching takes you to a page that displays administrative data about the tenancy.

This is admin data. Dashboards usually display user data, but should do so only if the user’s JWT token has been verified. Next, we’ll create:

  • A protected route that verifies the user before exposing the component
  • A UserDataComponent that relies on that protected route

An updated dashboard that displays the UserDataComponent

Implement a protected API route

This protected API route implements server-side JWT verification, which is crucial for securing server-side data access. We’ll need the jsonwebtoken package to verify the access token:

To securely handle sensitive user data, we'll create a new app/api/protected-route/route.ts file that is protected API route when the JWT token is verified:

Fetch sensitive user Data

UserDataComponent demonstrates client-side API calls with authentication tokens, aligning with the 'HTTP APIs' approach. However, it relies on proper server-side implementation for actual security. For fetching sensitive user data, we'll create a separate component that makes an authenticated API call. Create a new app/(secure)/dashboard/UserDataComponent.tsx file with the following code:

Update the dashboard with the user data component

Now, let's update the dashboard page to display user information. This dashboard component uses client-side data from Userfront, but doesn't inherently provide security. It should be used in conjunction with server-side protections. 

Security-charged component

Now you have server-side JWT verification in the protected API route that provides the necessary security for the UserDataComponent. Here's why:

  1. Token Verification: The API route verifies the JWT using the Userfront JWT public key, ensuring the token is valid and hasn't been tampered with.
  2. User Authentication: After verifying the token, it extracts the userId from the decoded token payload, confirming the user's identity.
  3. Authorization: While not explicitly shown in our example, the userfront.getUser(userId) call could be used to fetch user-specific data.
  4. Data Protection: Only after successful verification and potential authorization does the route return user data.

However, it's worth noting:

  1. The security of this system relies on proper management of the JWT public key and other environment variables.
  2. Additional authorization checks might be necessary depending on the specific requirements of your application (e.g., checking user roles or permissions).
  3. While this setup provides good security, always remember that security is a multi-layered concern. This should be part of a comprehensive security strategy including secure coding practices, regular audits, and following the principle of least privilege.

Conclusion

By following these steps and best practices, you can create a secure, authenticated Next.js 14 application using Userfront. Remember to always verify JWTs on the server-side before granting access to sensitive data or protected routes.

Some key takeaways:

  1. Use the UserfrontProvider to wrap your application and provide authentication context.
  2. Implement protected layouts to secure entire sections of your app.
  3. Always verify JWTs on the server-side before returning sensitive data.
  4. Use tools like environment variables to store sensitive information like API keys and JWT public keys and exclude them from check-ins.
  5. Take advantage of Next.js 14's built-in API routes for server-side operations.

By understanding and implementing these concepts, you'll be well on your way to creating secure, scalable Next.js applications with Userfront authentication.

Subscribe to the newsletter

Receive the latest posts to your inbox.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

By subscribing, you agree to our Privacy Policy.

Modernize Your Sign-On

Experience smarter enterprise sign-on tools & reporting.