Next.js App Router Authentication (Sessions, Cookies, JWTs)
Summary
TLDRIn this video, the presenter demonstrates how to implement basic session authentication in Next.js without additional libraries, focusing on creating, managing, and securing sessions using cookies and JWTs. The tutorial covers essential aspects such as login, logout, and session refresh, highlighting the use of Next.js functions and middleware. Additionally, the video explores using the NextAuth.js library for more advanced and abstracted authentication, supporting multiple providers like GitHub. The presenter emphasizes the importance of securing secret keys and touches on future updates and deeper topics like authorization and database sessions.
Takeaways
- 🔐 The video covers basic session authentication in Next.js without additional libraries, as well as other options if you prefer not to build your own authentication system.
- 🖥️ The example begins with a simple Next.js application setup, showing how to handle sessions in the root layout and index route.
- 📋 The session management involves setting up a login function that processes form data, creates a session object, and stores it as an HTTP-only cookie using Next.js's cookies function.
- 🔒 Encryption of the session data is handled with the Jose library, which signs the JWT (JSON Web Token) using a secret key. This key should be kept secure, ideally in an environment variable.
- 🕒 The session expiration is managed by updating the session cookie every time the user interacts with the application, ensuring it doesn't expire prematurely.
- 🛠️ Middleware is used to refresh the session on every request by decrypting the session data, updating the expiration time, and setting a new cookie.
- 📂 The video also demonstrates how to read the session information from the cookies using a getSession function, allowing the application to display user-specific data.
- 🚪 The logout function simply deletes the session cookie, effectively logging the user out.
- 🧩 The video contrasts the basic custom authentication setup with the more robust NextAuth.js library, which provides built-in support for various authentication providers like GitHub.
- 📚 The video concludes by mentioning additional resources and documentation on more advanced topics like authorization, protecting server actions, and integrating with other popular authentication libraries like Auth0, Supabase, and Clerk.
Q & A
What is the primary focus of the video?
-The primary focus of the video is to demonstrate how to implement basic session authentication in Next.js without using any additional libraries, followed by an introduction to using NextAuth.js for more complex authentication setups.
What is the purpose of the `login` function in the code example?
-The `login` function handles user authentication by processing form data, creating a session for the user, and setting it as an HTTP-only cookie. This session is encrypted using a JSON Web Token (JWT) before being stored.
Why is the session stored as an HTTP-only cookie?
-The session is stored as an HTTP-only cookie to ensure that it can only be accessed by the server, enhancing security by preventing client-side scripts from accessing the session data.
What role does the `encrypt` function play in the authentication process?
-The `encrypt` function is responsible for signing and encrypting the JWT, which contains the session data. This ensures that the session information is secure and can only be decrypted by the server.
How does the middleware in Next.js contribute to session management?
-The middleware runs before every request in the application. It updates the session expiration time by calling the `updateSession` function, which refreshes the session if a valid session cookie is present.
What happens when the `getSession` function is called?
-The `getSession` function reads the session cookie, decrypts it, and returns the session data. This allows the application to retrieve information about the logged-in user, such as their email address.
How does the logout process work in this authentication setup?
-The logout process involves calling the `logout` function, which deletes the session cookie using the `cookies` function in Next.js. This effectively logs the user out by removing their session data.
What is the advantage of using NextAuth.js over the custom authentication setup?
-NextAuth.js provides a higher level of abstraction, simplifying the implementation of authentication by offering built-in support for various providers like GitHub, Google, and others. It handles many aspects of authentication, including session management and route protection, without requiring the developer to write as much custom code.
How does NextAuth.js manage sessions differently from the custom setup?
-NextAuth.js abstracts the session management by automatically handling session tokens, CSRF protection, and session refreshes. It also offers a middleware with configurable options to control when and where the session management should run.
What are some key differences between cookie-based sessions and database sessions?
-Cookie-based sessions store session data directly in the client's cookies, often as an encrypted JWT. Database sessions, on the other hand, store session data on the server side in a database, with the client only holding a session identifier. This can provide additional security and scalability benefits, especially for larger applications.
Outlines
🔐 Introduction to Authentication in Next.js
The video begins by introducing the topic of authentication in Next.js, emphasizing that it is a broad topic with many facets. The focus of this video is on demonstrating basic session authentication without relying on additional libraries. The video will cover logging in and out, session handling, and provide a brief overview of other available options. The speaker mentions that the code and documentation will be provided in the description, and the application has been set up locally to guide through the authentication process.
📄 Setting Up Basic Authentication
The speaker dives into the basic setup for authentication, starting with the root layout and index route. The session-based authentication is implemented by creating and managing session cookies. The process involves logging in, retrieving session data, and displaying user information. The code uses server actions to handle login and logout, where the session information is stored in an encrypted cookie. The encryption is done using the Jose library to create a JWT (JSON Web Token) and securely store it. The expiration of the session is managed by setting an HTTP-only cookie, ensuring security by restricting access to the server side only.
🔄 Managing Sessions and Middleware
The video continues by explaining how session management is handled, particularly the update of session cookies with every request. The middleware file is responsible for running before every request, calling the updateSession function to refresh the session. The decrypt function is used to verify the JWT, ensuring that the session is legitimate before it is updated. The getSession function retrieves session information by reading the cookies, allowing the application to manage user sessions efficiently. The logout process is also covered, showing how the session cookie is deleted, effectively ending the session.
🛠️ Implementing Authentication with NextAuth.js
The speaker introduces an abstraction layer using the NextAuth.js library, which simplifies the implementation of authentication. This library supports multiple authentication providers, such as GitHub, Google, and Discord. The example demonstrates how to set up authentication using the GitHub provider, including sign-in, sign-out, and route handling. The code is structured similarly to the previous example but is more abstracted and flexible, allowing for easy integration of various providers. The middleware configuration is also explained, ensuring that session refreshes only run on specific routes, excluding static files and images.
📚 NextAuth.js Updates and Future Considerations
The video concludes by mentioning that the version of NextAuth.js used in the example is a beta version, which may have become stable by the time viewers watch the video. The speaker briefly discusses the depth of the authentication topic, touching on authorization and the importance of protecting server actions and route handlers. The video primarily covered cookie-based sessions, but other methods like database sessions were mentioned. The speaker encourages viewers to explore further resources, including new documentation and examples using various popular authentication libraries, and invites feedback on what topics to cover in future videos.
Mindmap
Keywords
💡Next.js
💡Session Authentication
💡JWT (JSON Web Token)
💡Cookies
💡Middleware
💡Encryption
💡NextAuth.js
💡Server Actions
💡Form Data
💡Route Handlers
Highlights
Introduction to basic session authentication in Next.js without additional libraries.
Exploration of Next.js root layout and index route setup for authentication.
Explanation of using cookies for session management, including setting and deleting cookies.
Introduction of JWT (JSON Web Token) encryption using the 'Jose' library.
Discussion on securing JWT with environment variables to prevent exposure of secret keys.
Demonstration of session expiration and cookie handling in Next.js.
Overview of the 'updateSession' function and its role in refreshing sessions.
Insight into the decryption process for verifying and decrypting JWTs.
Explanation of the 'getSession' function for retrieving session information from cookies.
Comparison of basic session authentication with a NextAuth.js abstraction.
Introduction to using NextAuth.js with GitHub as an authentication provider.
Discussion of middleware configuration in NextAuth.js for route handling and session refreshing.
Explanation of different authentication strategies, including cookie-based and database sessions.
Mention of alternative authentication libraries like Clerk, Lucia, Auth0, and Supabase.
Closing remarks on the depth of authentication topics, including authorization and protecting server actions.
Transcripts
Let's talk about authentication in Next.js.
This is a broad topic, and there's a lot that we could talk about.
In this video, I'm going to cover showing how to do basic session authentication in
Next.js without any additional libraries.
Then, I'll also show some other options you can use too, if you don't want to roll your
own auth.
So, let's get into it.
The code for this video will be in the description, and we've also published new docs for both
the pages and the app router, so go check those out.
But what I've done is I've cloned this application locally.
I've got it up in my editor, and we're just going to talk through some of the bits here.
First, we have our root layout, which hasn't changed from setting up a hello world Next.js
app.
This is just the HTML in the body of our application.
And then, I have our index route.
So, I have our page file denoting that route.
This is a server component, so we've marked it as async, and we're awaiting getting the
session for our application.
If there's a user, we're going to print out information about the user here; otherwise,
we're just going to say it's null.
Then, we have two different forms here.
We have one form that allows the user to log in, and it calls the server action.
It calls this login function and then redirects back.
And then, we also have the same thing, basically, to log out.
So, this is just a basic scaffolding of log in, log out.
There's, of course, a lot more that we can do here, but the real meat of understanding
the basics of authentication is going to be in the login and logout functions.
So, we've moved all of this library, everything related to authentication, into this one lib.ts
file.
Let's start with login.
So, the login function that gets called over here, I'll just type in [email protected], hit
enter to submit our form, and we see this information that is logged out on the right.
This login function is called; it takes in the form data.
I can read information from the form, like the email.
I can put some other additional information here on the user object in your application.
This is where you would probably talk to a database and look up information about the
user.
And once we get that information back, then we get to create our session.
So, we're going to define when we want it to expire through a new date.
We're going to make this session object, which is going to be encrypted, and it takes the
user and the time that it expires, and then we set this as a cookie.
So, Next.js has this cookies function that allows you to set and delete cookies.
So, we set this with the name of session, we pass along the session, we say when it
expires, and critically, we say this is an HTTP-only cookie, so you can only read this
on the server.
Now, we skipped over this encryption part, but this is really important.
So, if we go up to encrypt, you'll see that we're doing a couple of things here.
This is an asynchronous function.
It takes in the payload for our JWT, or JSON Web Token, and we're going to call this function
from this library here, Jose, which is going to allow us to sign the JWT based on the payload
and the algorithm that we want, when it was issued, when we wanted it to expire at, and
then the secret key that we're going to use for that encryption.
Now, here I've just defined it up top.
In your application, you probably want this to be an environment variable or something
that people wouldn't have access to, so definitely don't want this value to get exposed.
So, we take this, this is what's actually going to encrypt that JWT.
So, let's take a look at what that looks like in my browser.
I'm going to open up devtools, and I'm going to reload the page.
There's no session right now because it had expired.
So, I'll do [email protected], I'll hit log in, and we set this session key here.
So, let's take this value, this encrypted JWT, and let's pop on over to jwt.io.
So, I've pasted this in here, and we see on the right, it determines what the algorithm
was, it shows the payload of the data, and then it says, "Hey, if you want to verify
the signature, you need to put in that secret bit."
So, this is just a nice way of being able to kind of visualize that data, just a helpful
little tip.
So, the session is stored as a cookie here, and we said it expired in 10 seconds.
So, when I reload the page, it's expired, that cookie is no longer there; it's done.
If I log in again, [email protected], and I reload, what you're going to notice is that the value
of "expires" is getting updated every single time, and you would also see that reflected
in the decrypted value of the JWT that we're storing.
So, how is this happening, and why are we doing this?
Well, if we pop back over to our application code, and we look at the middleware file,
this file is going to run in front of every request in our application, and it's calling
this function.
It's taking in the web request, and it's calling "update session" with that web request.
So, let's pop back into our authentication file, where we've been kind of building our
own auth library, and we have updateSession.
So, it takes in that request, NextRequest is just an extension of the web request, takes
in that request, it looks at the cookies.
If there's no session, if there's no session cookie provided, you can just return back;
otherwise, refresh that session so it doesn't expire.
So, we decrypt that value from the session, we set a new expiration time, we tell NextResponse
that we're going to produce a response, a web response from this, and then on that response,
we set a new cookie.
Now, the bit that we skipped over here was the decrypt function.
So, let's go take a look at that.
Decrypt takes in this input, it uses Jose as well, too, to verify, based on the input,
based on the key, based on the algorithm that we encrypted it with.
If this, you know, is legit, we're going to decrypt it and return back the payload.
So, that happened down here, where we got back the value from decrypt, and then we were
able to update the cookie.
To round out our auth implementation, we need to read information about the request.
So, we talked about this getSession function when we first looked at the page, but what
exactly was this doing?
Well, really, it's just reading from the cookies.
So, we already showed how we were setting the JWT as a cookie for our session; all this
function is doing is just reading from the cookies, looking for that session value, and
then decrypting the value.
So, that's how, inside of here, again, if I go back to the browser, I do example.com,
this could look at my database or something.
That's how this getSession function is able to get back information about the session.
Now, if I click log out with the server action, what's going to happen, if you watch my console
over on the right side, you see that the cookie was deleted.
So, it was removed out of my cookies.
And if we click into the logout function, all this was doing was calling the Next.js
cookies function, and it was essentially destroying the session.
So, this file is really all it takes for the most minimal session-based authentication
inside of a Next.js application.
You're reading your values inside of your page, you are using a middleware to refresh
that information, and it, of course, can get way more detailed than this.
But I think it's helpful to step from just a really basic example, and we can add complexity
on top from there.
Now, I want to show what an abstraction on this model looks like.
So, the basic model I showed is effectively a very light version of NextAuth.js, which
is a popular community library.
And I want to walk through another example that uses the same setup but using NextAuth.js.
So, I've got that example open here on the left, and I've got it running in my browser
on the right, and we're going to see, you know, a lot of similar things, just one layer
of abstraction higher.
So, I have this auth file, auth.ts, it's going to set up some sign-in, sign-out, auth methods,
and also some route handlers for our application.
And it's going to say that we're using the GitHub provider for auth.
Those route handlers are under api/auth/[...nextauth].
So, this catch-all route that is going to scaffold a bunch of those route handlers for
us, for the library to use.
So, we take the GET and the POST from that, you know, central auth setup, and we scaffold
out these routes.
And then, back in auth, we don't really have to do anything else to get this working with
GitHub, but since this is, again, a layer of abstraction higher, this works with a bunch
of different auth providers.
It could be GitHub, Google, Discord, really any provider you want to use.
So, let's go look at the index route in the page.
So, for our page, we are calling await auth, which is basically similar to getting the
session.
This was the value that was exported from our auth file.
From the session, we get the user and the email, and then we render out this information
below.
So, I click sign in with GitHub, I've already configured and authenticated to say, "Yes,
I authorized GitHub," so it skipped the modal, but I say, "Okay, welcome, my email address
here."
I can click sign out, and when I look at these other components, they're very similar.
They're forms that have a server action.
They call a signin function or a sign-out function.
The signin one takes in a string, which is the provider that I'm using, in this instance,
GitHub, and sign out just, you know, deletes the session, basically.
So, for example, if I open up the cookies, this is for localhost:3001, running on a different
port.
Making this a bit bigger, we can see there were three cookies created.
There's the session token, which is that encrypted JWT; there's the callback URL, and then there's
also a csrf token for increased security.
So, this is all abstracted away for us; we don't need to do anything here.
Just like in the previous example, there's a middleware, so that the session can be refreshed
when you reload the page.
This one also includes a config option, with a regex for what routes we want this to run
on, so it's not going to run the middleware on static files, or next/image, or on the
favicon.
So, that's probably good to also include as well, too.
It's worth noting that, depending on what time you're watching this video, these changes
might already be stable.
I'm using the latest beta version of the NextAuth.js package, that's been totally refactored for
the app router, to really simplify things.
So, the code for this is down below, if you want to get started on this version.
It might already be stable by the time you watch it, though, so just wanted to quickly
mention that, too.
The topic of authentication goes super deep.
There's not only authentication; there's also authorization.
So, we cover some of this in our new docs.
We talk a little bit about authorization and protecting server actions, protecting route
handlers.
In this video, we talked about cookie-based sessions, but there's also database sessions,
and, you know, there's really a ton of stuff here.
We also include a bunch of examples with other popular authentication libraries, whether
it's using Clerk, Lucia, Auth0, Supabase, or any of these here.
Worth checking out, if you'd like to see us talk more about authentication.
Definitely let me know in the comments what you want to see with Next.js and AuthA, or
AuthZ.
We can go in more deep context here, but hopefully, this was a good introduction into just a very
basic cookie-based session example.
Let me know what you thought.
Peace!
Weitere ähnliche Videos ansehen
Learn JWT in 10 Minutes with Express, Node, and Cookie Parser
NextJS + Firebase Tutorial 🔥 // Hooks, Firestore, Authentication & Functions!
Next.js Fetch Data the Right Way (with a Data Access Layer!) (Security, Auth, Cache, DTO)
#32 Spring Security | Custom Configuration
NestJs REST API with MongoDB #4 - Authentication, Login/Sign Up, assign JWT and more
I Tried Adding Google Auth To a Python Web App | ft. Streamlit
5.0 / 5 (0 votes)