Managing Authentication in Next.js

Recording available for Multipass and Full ticket holders
Please login if you have one.
Rate this content
Bookmark

Next.js is a compelling framework that makes many tasks effortless providing many out-of-the-box solutions. But when it comes to authentication and user security, it's our mission to make it reliable, secure, and efficient. In this workshop, we'll focus on different user authentication and session management approaches, starting from a custom authentication strategy (that we will build together), and ending learning how to identify and integrate the right auth provider (Auth0, Firebase, etc.) for any app.


Table of contents:

- A brief introduction to Next.js

- Building an authentication mechanism from scratch

- Why we should avoid custom authentication

- How to identify the proper authentication mechanism and provider

- Integrating NextAuth.js, Auth0, Firebase, or any other provider

155 min
22 Feb, 2022

Comments

Sign in or register to post your comment.

AI Generated Video Summary

Welcome to the workshop on managing authentication in Next.js. We'll cover custom authentication methods, integrating Firebase, and the pros and cons of different approaches. We will explore bcrypt for password hashing and comparison, and JWT tokens for authentication. Iron Session will be used for cookie management. The importance of server-side rendering and protecting routes will also be discussed.

1. Introduction to Authentication in Next.js

Short description:

Welcome to the workshop on managing authentication in Next.js. We'll cover custom authentication methods, integrating Firebase, and the pros and cons of different approaches. The workshop includes a Q&A session, and I encourage you to ask questions at any time. Let's get started!

So, welcome, everybody. This is my first workshop at Node Congress. I'm incredibly excited to be here, and before we start, I'd like to introduce myself. First of all, I have two screens, so if some of you have to ask me something, you see I'm not looking at the camera. It's because I have a second screen. So, no offense, I'm just writing code on the second screen and looking at you on the other one. So, I want this to be clear. No offense. Really sorry about that.

Okay. So, as I was saying, welcome to the workshop, managing authentication in Next.js. So, before we start, let me introduce myself. I am Michele Riva. I work as a senior software architect at NearForm. We are the main Node.js maintainers and we have a lot of expertise in Node.js, Next.js, React, whatever happens in the JavaScript playground. And we are hiring, just in case. I'm also the author of the real world Next.js book, which will be published at the end of this month and we'll get there in just a second. I'm also a Google developer expert and a Microsoft MVP. But talking about my book, I prepared a 25% discount code for everyone of you willing to buy the hard copy, so the printed one, which is typically more expensive. So, I wanted a discount. You can use the 25 Next.js code at checkout on Pocket Publishing. Please, in case you want to use this discount code and you can't remember where to get it, please just write me in the chat. I will write a reminder on Discord so that you have, like, a couple of weeks to use this discount code.

So, what are we going to do today? This is a brief agenda of what we're going to do today. First of all, I want to give you an introduction on authentication, authorization, and how to deal with that in Next.js and JavaScript apps in general. Then we will start looking at the custom authentication methods, and we will be concentrating on the good, the bad, and the ugly of writing custom authentication strategies. Then we will have a break of five minutes, so you can drink a glass of water, you can rest your eyes for a moment after one hour straight on the workshop. Then we will be back again trying to understand how to integrate Firebase, how to zero, or whatever we want. So, the point for this workshop is not to teach you how to implement a specific authentication method. It's about telling you what are the pros and cons of doing this from scratch, adopting a framework, where we typically fail, and all the security concerns about custom authentication. And then, if we have time, we will have a Q and A. Please note, this workshop is meant to be three hours long. And as you can see, we only have two portions of 60 minutes. And there's a reason why. That's because 60 minutes, it's me talking. I want to interact with you. So, if you have any question in any moment, please, feel free to stop me. Ask me as many questions as you want. And until it's not clear what I'm talking about, we won't proceed. Because I want every one of you to be aware of what we are thinking. And you know, I'm not a native English speaker. So, sometimes I can find it difficult to find the right words. I do understand this. So, please, please, please block me if you see that I'm not telling something that you can understand, of course, because it's my fault. So, that said, I feel like we can get started. If you want, you can follow along with me. I've prepared some code. And I'm gonna send you the link on Discord. So, if you haven't already, Daria has put a link on the Zoom chat to access the Discord room. So, every communication, I'd like to send every communication on Discord. So, that it's easier for us to gather here and share communications and whatever. I will always keep Discord open for the entire workshop. So, if you have questions and you can't use the microphone, don't worry, just put a question on Discord. I will keep an eye on it. So, I will give you, like, a couple of minutes to joining Discord. If you haven't already, you can find, again, you can find the link on the Zoom chat. Okay. I see Eveline asking for the link. So, are you asking for the link to joining Discord or book? Oh, okay, book. So, yeah, let me send you. This is the link, and let me send you the discount code. Again, you have a couple of weeks to redeem your discount code, so feel free to use it and share it with your friends, colleagues. Not a problem at all. Feel free to share with whoever you want. Okay, I can't see. Oh, it's 25 discount! So, I hope this can be helpful for everyone. Okay, so let me show you the boilerplate code before we start doing anything. So, as I was saying, I've created the.00authworkshop boilerplate, which is a standard Next.js app, which is linked to an Hasura GraphQL endpoint for retrieving data. Don't worry about GraphQL, don't worry about Hasura, or whatever. It's not important at that stage. We want you... I just use it as a method, as an easy method for retrieving data, which is quite important at the moment. You know, so let me start the project. Move a bit screen. Okay. One thing to consider, I'm currently live on Zoom, so the compilation could be a bit slower. It's not because of Next.js, but because of bandwidth and, of course, computing power, which is reserved to Zoom to currently work. So this is the boilerplate code I created. And as you can see, it's a kind of Amazon, you know? It looks like Amazon, but it's not really. And we basically have some products. We can enter the products, of course, see how much they cost. We can add them to the card. Oh, but we cannot because we are not authenticated. So what we want to do is to allow people to add products to the card when they are authenticated. They can log in and right now, as you can see, nothing happens if I click. Now I'm clicking, we can register and again, I'm clicking and nothing happens. And that's it. So it's really simple. I've also created a couple of private routes which now are public and we will try to make them private in just a second. So if I go on profile, as you can see, it doesn't require me to be authenticated right now, which is an issue and we are going to solve this.

2. Addressing Public Information in Recent Orders

Short description:

We need to address the issue of public information in recent orders. Let's use draw.io to visualize the solution. Feel free to ask for clarification at any time.

But we can go on recent orders As you can see, it's loading, dynamically loading, recent orders and we have like okay, this is what I bought so I can go back and see all the products I bought, the date, the order ID and the order total. I can change the password and look at my profile. And as you can see, this is not my actual profile, but my actual address, but I'm just showing my name and the address. So all those information are public right now and that's clearly an issue. So how do we secure those information and that's the billion dollar question right now. Let me go. Oh my god, there's zoom. Okay, sorry, I was okay, so I'm gonna use draw.io to draw some diagrams for now so that we can understand what we want to do. Please, again, remember, block me whenever you want and ask for more explanation if you need it. If I'm not explaining something well enough please block me and I will repeat in other words. Please, this is really important.

QnA

Securing Routes and Building Authentication

Short description:

Let's see how to secure the routes in our application. We have public and private pages, and we want to move some routes to the private section. We will start by building a custom authentication method. Keep in mind that writing a custom authentication method is not easy, and there are companies investing in secure and reliable authentication solutions. We will also need API pages to handle authentication. Let's interact with the audience to gather ideas on typical APIs needed for website authentication.

So okay, let's see how many routes do we have and how we want to secure them. So this, let me zoom a bit, maybe a bit less. Okay, so this will be our application. This is our Node.js server. So let's color it with green which is the Node.js color. So whatever we have inside that page it's public at the moment. So we can try to divide that into two separate pieces, like follow. So we can do the, say the violet one will be the public and the red one will be the private. So we have some, you know, some routes, we have some pages that are currently public, we want to move them into the private one. Let's see how to do that.

So first of all, so first of all, we have the homepage, which will always remain public. As you may know, of course, we have the single product page. So product page, which will always remain public, no doubts about that. As you can see the cart page, we couldn't add anything to the card, because we weren't authenticated. So cart page is private. Let me write here, public. Oops. And this is gonna be private. Okay. So the cart page, the profile page, so, profile page, recent orders, change password. And the last one will be the account page. So as you can see, we have one, two, three, four, five, six, seven. We have seven pages. And only two of them will be public at the end of the day. So we want to make sure that all the private routes will be, of course, private. And how we do that. So as I was saying during the introduction, we will start by building a custom authentication method from scratch. Which is terrible. I want to say that from now on, please keep in mind that writing custom authentication method is not easy. There are tons of companies, such as Firebase or Auth0 or Okta and AWS, that are investing a serious amount of money to keep authentication secure, and reliable, and easy to, you know, easy to implement and really hard to hack. Which is incredibly important. If there's anyone of you that is working on a context where GDPR, so data protection regulation for European countries, is involved, this is especially important because fines are really high. So, if you're breaking the GDPR rules, your website cannot land the European market. This is incredibly important. Please be aware of that. So, what are we going to do? So, as you can see, we have just defined a couple of public pages, but it's not enough. We will need some API pages at a certain point. Let me copy and paste this block. Let me make it a bit more appealing because I will be sharing this with you at the end of the workshop. Let's make it yellow. So, whatever we have inside the yellow box will be our API pages, where we will be handling our authentication.

So, let me try. I would like this to be a bit of a kind of workshop where I can interact with people. So, let's say that we want to implement authentication in our application. Where should we start? Can anyone of you raise their hand if they know one typical API that we may need for implementing authentication on a website? Please, raise your hand on Zoom and I will give you the word. Otherwise, you can also, you know, write on the chat, if you can use your microphone or on Discord, of course. So, please. Oh, okay. Sorry, I see you're raising your hand. Please tell me how to pronounce your name correctly. I don't want to mispronounce it. And then, go ahead. I fear you're on mute. Me? Or we have multiple people raising hands. Okay, no, it's you. It's you. Sorry. Basil. Basil. Okay. Awesome. Awesome. Nice to meet you. Nice to meet you. I would say we need a register route to register in Macau. That's correct. That's correct. So, let's put the first route we will be implementing, so the register. Awesome. So, thank you, Basil. You can lower your hand. And I would like to ask Amandeep if he has some other idea. What as what we need? So, for API that would be an authentication API that would, you would send some credentials and respond whether they're not. Yes. So, you mean log in, right? Yes. Awesome. That's correct. So, we will need a login API. What else would we need? Is there anyone else with any idea? Log out. Sorry? Log out. Log out. Yeah. That's correct. I wasn't thinking of that, but you are absolutely right. Okay. Thank you, Amandeep. I would like to ask someone else if there's any idea because we don't… I mean, I wish we need only three routes, but it's not like that. So, we need more. Checkout order. Yeah, checkout order, but it's not about authentication.

Routes and Functionality

Short description:

In addition to the routes we've discussed, we will also need a session route for retrieving the current user and a refresh token for JWT authentication. While we may not cover email verification and password reset in detail, I will provide an overview. Let's proceed with the register and login routes for now.

You're absolutely correct for the context we are building our application in, but I'd like to know if there's something else for… I see Santiago, validate account. Okay, that's correct, so I put in my email, for example, and I want to validate my email. That's absolutely correct. So, I would call it email verification. That's correct. Resetting password, that's also correct. Awesome. Do we miss something? I think we are… we are okay. And get user, of course, refresh token. Awesome, I see people already having experience in that field. That's absolutely awesome. So, you're both correct. We would need many other routes, such as the let's call it, session route, that gives us the current user, just like Pavel was saying. We will need the refresh token, just in case we are using JWT, which we will be using, so that's absolutely correct again. We will actually need others, but as for now, we will be concentrating on register, so let me colour this in orange, and we will create the login. Then we will create the session, of course the logout, and I will pause for a moment, because I'm not sure we will be digging into email verification reset password, even though I will explain you how to do that. If we have time, we can write it, otherwise we will need to move on. It depends on how things go. Let me open a couple of notes.

Implementing Authentication with Registration

Short description:

We want to implement authentication using a simple flow. Users can register by providing their email and password. The server checks if the email already exists in the database. If it does, the request is rejected. If the email is new, the password is encrypted and stored in the database. A confirmation email can be sent in a production environment. To confirm the email, a unique token is generated and stored in the database. When the user clicks on the confirmation URL, the server verifies the token and email address before confirming the email. Let's proceed with creating the Register API using GraphQL requests and the Bcrypt library.

Okay. I've taken some notes just not to waste your time. Okay, so how do we want to implement the authentication? This is the schema of what we want to do. Let's take a look at Heroku for a moment where I have the database. Okay, so this is what we have today inside the database. And again, we won't be digging into database and schema. You will see many nonsense at the moment. But it's just because we want to concentrate on authentication. Nothing more. So whatever you see here, it's not really important at the moment. Please be aware of that.

We have a number of orders. And if you go here in profile, orders, you will see them here. So, as you can see, a single order, it's basically a relation to a user, given date, and our array of products. We have our products, as you can see here, with a number of information that we are not but they're quite handy. So, they are nice to have. Then we have users. So, let me delete the users so that we can start from scratch. So, what we will do is the following. We have a user that we will call, let's call it Alice. You know, when you're dealing with communication protocols, you typically use Alice and Bob as names. So, we will be using them too. So, we have Alice that wants to log in to our server. So, she doesn't have an account. So, as a first thing, she has to create an account. So, she has to go to the register route. Okay. So, give me one second. I need to go on.

Okay. So, Alice needs to register. In order to register, she needs to pass a couple of data. At the moment, we want things to be really easy. So, she will pass email and password. Okay. So, this is what will be she will be sending to the server. The server will need to look if the username and password already exist inside the database. If they exist, we cannot accept the request, because you know, the email is unique. So, email exists. At this point, if the email exists, we can go back to the user and say, I'm sorry, you can't do that. Oh, it's really, really ugly. So, let's do that. Email exists. In that case, 401, unauthorized, which is not correct. We should use maybe 422 or, yeah, let's just say that you're not authorized to complete that action, which is not 100 percent correct in HTTP verbs, but let's keep things simple. If the user doesn't exist, then we can proceed doing a couple of more things. So for example, first of all, we will need to get the password and encrypt it. Oops. So we will encrypt the password. Yeah, let me use password. Then we will store it inside the database alongside the user. Then we will be sending a message to the user. So, that looks quite simple, right? But this is the most simple flow you can aim for. And it's not even complete, because we will be finishing here, but in a production environment, you will need to validate the email as we were saying. So at this point, we will be ending, so this is red, because we won't proceed any further. We don't have time. But in a production environment, we will be sending a confirm email. So let's run this first. And how do we do that? And this is interesting. If you want to confirm an email, we want to create a Univok token inside the database, and maybe we can try doing that. We will store a unique identifier inside the database. As a query string to our URL. And when Alice clicks on that URL, the server will say, okay, I have a request for that email address with that token. Is there a user with that email address and that specific token inside my database? If so, then we should confirm this email. Otherwise, we get an error. Quite easy. All right, everybody? Please let me know if you can follow, if I have to repeat again. So, that's quite a typical flow. After that, we consider our email to be confirmed and the user can start doing whatever they want. Yeah, let's do that. It wasn't planned for that session. But we're going to do that because it's really exciting. So, maybe if we have time, we're going to do that. So, okay. Awesome. Let's start from there. Let's create Register API. So, let me take my Visual Studio Code. Okay. So, first of all, we will need, as you can see, we are using GraphQL requests. If you want to follow along with me, I'm putting the API endpoint in the Zoom chat so that you can follow along with me writing code. So, as you can see, we are using GraphQL requests for doing server-side and client-side requests using GraphQL so that we are connected to Hazura. If you're not familiar with GraphQL, please don't worry, I'll be explaining whatever you need to get started with it. Okay, so that's just for saying. We will need a couple of libraries for proceeding with that. First of all, we will need to install Bcrypt. So yarn add Bcrypt. Is there anyone knowing what Bcrypt is? I can't believe no one knows. I know there's someone knowing it. Please raise your hand if you know it.

Introduction to Bcrypt and Password Security

Short description:

Bcrypt is a hashing algorithm and function used to encrypt and compare passwords. MD5 is not secure due to its vulnerability to brute force attacks. Salting provides an extra layer of security, but it is not enough to protect passwords. Rainbow tables can crack passwords with salts. Bcrypt generates different hashes for the same password, making it a more secure option.

Okay, let me do the opposite. Please, put your thumbs up, reaction if you don't know what Bcrypt is. Okay, thank you, Oscar. Can all the other folks hear me? I'm sorry. I'm starting to fear that. Okay, thank you, Billy. So yeah, I guess you can hear me. Don't be shy, please, guys. This is a secure environment. No worry.

Okay, so let me show you about Bcrypt. So this is the library we are gonna use. Bcrypt is a hashing algorithm and function used to encrypt and compare passwords. So let me show you something. How many of you are familiar with MD5? Ossum, Santiago, Amadip, Pavel, Hamet? Sorry for my pronunciation, Billy Ossum. So for those who don't know, MD5, it's a cipher. It's an encryption function that takes an input, a string input, and producing a hash as an output. What does it mean? Let's see it in the screen. So let's say, hello, we produce the following hash. If I say, Michele, which is my name, it will produce the following hash. But we can't store these inside our database. Why am I telling this? Let's see the first case. Hello. This is the MD5, the resulting MD5. Let's open another tab and put hello. Oh, as you can see, I'm switching between two different tabs and for the given input, we will always get the same output. Can you see the problem?

If there is a vulnerability in our system and we store passwords using MD5, then there is a highly security concern here, meaning that there might be someone exploiting the database, downloading all the users. And if there are two people, for example, using the same password, which can occur, they will have the same signature. Or, we can brute force. Meaning, okay, I want to, let's do that. I have this, you know, let me take this, okay. I have the following hash. I don't know what the password is so I can try with H. Is the same hash? No. Let's try with HE. Is it the same? No, so let's try with H-E-L-L. Is it the same? No, let's try with H-E-L-L-O. Is it the same? Yes. So what's the problem with that? I can brute force this password, get the hello, which is your current password, and I'm 100% sure that 99% of every internet user out there, it's using the same password on Facebook, Twitter, Amazon, bank accounts and wherever. So that's a bad security issue. Never use MD5. Please don't do that. That's really, really important. Amanda says, we have various brute force tools available which can give results in seconds. That's absolutely correct. Thank you, Amanda. That's absolutely correct. We have a lot of problems with cryptography in general because we're also leading to the quantum computing era where let's see if we can find it, brute force password calculator. I wanted to show you something. Thank you, Amanda. That's really interesting what you're saying. Okay. So let's say I have a password which is stored as an MD5 and has five, sorry, four uppercase letters, four lowercase letters, one number and nothing more. This is the number of combinations. So it's two billion, more than two billion combinations, you know. We can crack this in 40 hours. So you see what the problem is. I mean, if I have an entire database of people and I can get this password in just 40 hours, that's a problem. I mean, that's a big security concern. So that's why I don't want to use MD5 and I don't want to use two-way password encryption, meaning if I give you twice the same input, I want two different outputs. Are you all all right with that? Do you have any question? All right, I will proceed, thank you. Okay, so we will be using BigCrypt. Pavel said, but we can concatenate some secret string to the password. You're correct once again and that's called salting. So we use salting proceeding that way. So I want to explain this to people maybe not being familiar with that. So I can use like, let's say, this is my password, hello. So this is user's password. And I can also use, let's say, nojs as a salt. So wherever the password is, I will use nojs-hello. Hello. So as you can see, the output will be quite different. And what's the problem with that, Pavel? The problem is once I crack this password and I crack like three or four different passwords inside my database, I will see the salt in clear text. So I will notice that we prepand or append some other charters to the password. So eventually I will be able to understand which part of the password it's your salt and which part of the password is the actual password. So that's the problem. Salting in that case, it's not enough. I mean, it's an extra layer of security, but it's not really enough. And also there are rainbow tables that can solve this password. Sorry, this problem. I don't know if I can see a nice image for that. Okay, I don't want to dig into the rabbit hole, but there is an attack called a rainbow table that it's able to crack password with salts. By analyzing the Md5 hash, so it's not a proper way to protect your password again. It's a extra layer of security, but it's not enough, sadly. So why are we using bcrypt? That's the interesting question for the moment. We're using bcrypt, because if I give bcrypt the same password twice, I won't be able to get the same hash as a result. So that's really important. If I give bcrypt the same password, like 10 times, I don't want it to give me the same results. So let me show you how it works. I've just installed the package.

Exploring bcrypt and Next.js API Routes

Short description:

In this section, we explore the bcrypt library for password hashing and comparison. We generate multiple hashes using bcrypt and discuss the benefits of using salts. We then demonstrate how to compare plaintext passwords with hashed passwords using bcrypt's compare function. Storing hashed passwords in the database is crucial for security. However, it's important to note that implementing custom authentication strategies can be risky. We will analyze the pros and cons of this approach. Next, we create an auth folder in the pages/APIs directory to house our authentication strategies.

As you can see, you're at bcrypt. Let me go here and create a little file, like test.js. Let's import it. I hope the screen is big enough. Please let me know if I have to magnify it. Okay. So this is my password, and it's hello. Really simple. So for i equals zero, i is less than 10. I plus plus. So let's generate 10 different hashes using by crypto. So the crypt dot oh yeah, sorry. As Pablo was saying, and it's completely correct, we can use a salt to enhance our password and using salts inside bigryph makes the password even more secure. So we should always use salts anyway. So salt, it's equal to bigcrypt dot gen salts. And we can use like a number. The higher the number is, the more complex the final password will be. And of course, the more it will be slower to generate the password. This is returning a promise. So let's wrap this into an assync function. I wish top level await will land very soon. So await, we are generating the salt. Then let's just do console log await, bigcrypt dot hash, hash. And we will use my password and the salt. So let's see how it works. Okay, awesome. So as you can see, we give the same password 10 times and we get 10 different password in return. And now you may be thinking, okay, that's great. I mean, no one will be able to get the original password from there, but how do we do? Right? That's another interesting question. We don't. We don't need to. We just want to do the following. We have our password, so let's do that. Let's remove the loop. Let's remove this and say const hash it. It's equal to bankrupt hash. Then, by default uses SHA-256. Yes, Santiago, that's correct. That's the algorithm we are using by default. Let me copy paste it here because I can't pronounce this correctly. So this is the algorithm we are using. Great, Santiago, thank you. So let's see for a moment what we are getting now. This is an example, okay? And we don't want to reverse engineer the password. We just want to say, Dear BayCrypt, thank you a lot for helping me. But now I have this hashed password. I have the plaintext password here and I have the hashed password here. Can you compare them and tell me if it's possible that the plaintext one is the same of the hashed one? So that's what we are doing with, you know, BayCrypt right now, so let's do that. Const is correct. We can do BayCrypt await, compare, and as you can see, it asks us to send a couple of parameters, plaintext password, and the hash. So my password, and hashed. Can you see what we are doing? True! So we can do the following. Is my, let's say, is hello, is goodbye. Let me show you what we are doing. So basically now I am giving the original password to the compare function, and a new password which is wrong. Because as you can see we are comparing with the hashed one, which is hashing the original password. So let's see how it works. Is hello true? Yeah, it's working. Is goodbye false? It's not working. Also, we did it. We did it. So that's what we are using. After the user sends us email and password, we will be storing that data inside of the database. So the password will always be stored as hashed. And again, I want this to be very clear. Please, if you have to implement authentication from scratch please try to find any other possible solution. It's incredibly risky. Unless you're a professional working in the authentication strategies for like every single day in your current company. Unless you're in that situation I would discourage you to adopt custom authentication strategies because it's really risky. I want this to be very clear. I'm just showing you a possible way for doing that but we will also analyze the good, the bad and the ugly of that approach. Please be aware of that. Okay, so let's do this. Let's delete test.js. Let's go in pages, APIs and as you can see, it's an empty folder. Let's create an auth folder which will contain the authentication strategies. Register. I'm sorry, are you all familiar with the Next.js API routes? Okay, Santiago. Awesome. Amandeep, if you're not familiar with that, please use another reaction right now. No. Oscar, no. Okay, great. I will explain this to you. Billy, okay, okay. It's not a problem. So, Next.js allows you to use pages for rendering HTML content. For example, we have the index page, which, as you can see, takes all the products from the database and produces an HTML as an output. So, this is a Next.js, a typical Next.js page. But we can use API routes to create rest APIs inside of our Next.js project.

Sending Data for Registration

Short description:

In this section, we explore the process of sending email and password data to the server for registration. We ensure that the email and password are present and handle missing parameters appropriately. We also perform a simple validation on the password length. It's important to note that this validation is not suitable for production environments. Instead, use more stringent validation methods.

And it's quite simple, actually. We can do the following. Export default function handler. Let's make this async. Just like in Express.js, Fastify, Coa, or whatever, we get access to request and response. And at that point, we can say res json and say hello and word. Let's see how it works. Oops, not this one. Okay. Yarn Dev. Let's open the project. So as you can see, we are inside API Auth register. So we can now go here and say API Auth register. Hello words. Hello word. Just like we did, you know? If you go back here and say, Hello word, and we say, I am Michele, for example. And we refresh, I am Michele. Here it is. Easy-peasy, isn't it? We can use this to communicate with the database. So one important thing, why do we want to use API pages? Because API pages don't get rendered on the client side. So browser, it's not involved in the computation of whatever you see here. So this is 100% server side. And I won't tell this enough. Never, never, never communicate with a database from the client, from the browser. If I can teach you something today, it's to never communicate with the database from the browser. Always do that from the client, please. And that's really important. Okay. So we need to build our REST API. We will be using Insomnia. So as you can see, I made some tests today. We want to send email and password to our server, and we will get registered. So let's do that. First of all, we've seen we are sending json data. So email and password. Okay so const email and password. We can extract them from request.body. Why are we using body? We could use query, but that means that we could also possibly accept get requests, which is really, really bad. We want every sensitive communication to be communicated using post requests, which get encrypted by SSL. So please never send get requests, including sensitive data. Always use post requests, which get encrypted. And, okay, so we have email and password, but there must be some annoying problem, you know, people, maybe someone uses username and doesn't put any password or vice versa. So we can handle this. If we don't have email, or we don't have password, just return, let's say res, so response, status, status, 401, unauthorized for the moment, res. JSON, success, it's false, oops. And we give a message, missing required parameter. We don't tell which parameter is missing because we don't want to expose how we manage things, so don't do that. Just say we're missing something. Then we return. Okay, so let's try this. Let's just return like. So if we send everything, we will get success, true right now. So if we go here and we pass email and password, success, true. We are in that situation. But if we do that, oh. Invalid JSON, okay. I made something wrong here. Let's see what's going on. Why it's giving me, oh, I'm sorry, I left a comma here. Here's why. Okay. Success, false, missing required parameter, and that's correct. We didn't put the password. That's correct. Awesome. Please stop me if you want to, more explanation on that process. Okay, so now we need to import by crypt. So import crypt from the crypt. So, now we may want to do some validation on the password. Let's do that really quickly. We can just create a function like function, validate, password, pass the password as an input, and we can say, if password length it's less than say, six, return false. Otherwise we do return true. Which is a very silly validation. Don't use that in production, but it's just, you know, to let you understand the process here. It's not about validation. So, if the password is not valid, we can just copy paste this. And, with the message, oh, let's do 500, whatever. So 500, whatever. The correct would be, yeah, four, okay. We should use this, sorry. I had some confusion. So, a processable entity. So let's use 422. Message, password is too short. We can try this right now. Let's try with hello, which is five charters. Oh no! Password is too short. So as you can see, we are also validating the password in a very silly way. Don't do that in production. Do something more strict.

Checking User Existence and Hashing Password

Short description:

We need to hash the password, but before doing so, we check if a user with the given email already exists in the database. If the user exists, we avoid hashing the password. We can use Hasura to count the users with the given email. If the count is zero, we can proceed with user registration. Otherwise, we abort the process and return an error message indicating that the user already exists.

But this is something. Okay, let's go ahead. We now want to hash the password. But before we do that, we have to understand that hashing the password, it's a very expensive function. And that's because it requires a lot of resources. The first thing we should do is to go on the database and say, dear database, please let me know if there's a user with that exact name, oh, sorry, with that exact email. If there is a user, we will avoid hashing the password. So we have to avoid some expensive computation before doing it. We want to make sure that we don't try to override a user. So we can go on Hasura, and that will be really simple. Let me write the Santiago comment first. A pretty good use case of the API that one can create Next.js is using this API as an intermediary layer between the client at the back-end, allowing us to apply patterns such as back-end for front-end, that's absolutely correct, or even Strangler pattern. And this helps a lot, reducing the complexity in the UI side, delegating the data processing and mapping to the server side. Thank you, Santiago, this is awesome. This is 100% correct. I do agree with everything you said. That's... You should be here speaking, because that's absolutely true and explained in a very good manner. Thank you a lot. So, user exists. We pass an email as an input. And we can try doing that. So, please give me all the count. Let me show it. Okay. I'm going to tell you what does it mean. So we're basically asking the Hazura server to count all the users with a given email. Please note that the email is Univoke. So we can only have one user with that email. So we can try, we can test this API by saying email, it's equal to michele.riva at nearform.com. Count zero, of course, because there's no one with that email. So if that is the case, we can register the user. Otherwise we won't. Okay, so let's copy this. Let's import, oops, let's import our GraphQL from GraphQL request. Let's try the query. It's equal to GraphQL. And we put the query, we just created and tested. So now we can create a function like function, user exists, we pass an email and we import the GraphQL client. Oops. Okay. So as you can see, I'm exporting the client right now, the GraphQL client. So we are basically assessing the GraphQL client from here. This would be async. So an async function, and we say await. Or let's say const, let's see what does it return. It returns a user aggregate. So we can do that. And that is equal to await GraphQL, request user access. So we are using that query and we are passing a variable. So as you can see here, we are using a variable with the dollar sign. And one way to use a variable inside a query is to pass it as a second argument inside an object. So we pass email and we can return Boolean of user aggregate. I can't remember. Oh yeah, here is.aggregate.count. What does it mean? It means that if you're returning Boolean of zero is false. Oh yeah, Boolean. It's false. If we return Boolean of one it's true. If we have like this many users we have other problems to solve. So we should either have zero or one in general. So that's what we are gonna do. Now we can say that if await user exists, so if in server database we already have at least one user with that email, then we should abort and say rests.status to be 422 and send them error message like user already exists.

Advantages of GraphQL

Short description:

Someone asks about the advantages of GraphQL compared to GRPC. The speaker explains that while GRPC has performance benefits, implementing a GRPC client in JavaScript can be challenging. GraphQL, on the other hand, offers standardized communication between clients and servers, allowing for flexible queries and the aggregation of data from multiple sources. The speaker believes that GraphQL will eventually replace REST due to its power and popularity. They encourage the audience to learn more about GraphQL.

Someone says, thanks Mikele, sorry it's late and need to get up late. Oh, I'm sorry to see you leaving. Please look at the recording, connect with me on Twitter. Let me write to you all my Twitter here. So you can reach out directly to me and I will be giving you whatever you need, basically. So if you need help or something, please reach out to me here. Awesome, have a nice day Amandeep.

So hope to hear from you. So Santiago says, in your experience, what do you consider what are the advantages of GraphQL compared with GRPC? Wow! That's a good question, actually. So GRPC has many pros, such as, you know, performances, mainly related to performances and communication between multiple clients, whatever. But if you want to implement a GRPC client on JavaScript, it's like hell. I won't be recommending you doing that. GraphQL, it's a protocol that allows you to do multiple things. For example, let me try to explain you. For example, we may have an API such as I don't know, let's pretend we are Facebook, right? So please give me all the users. But then we may like to have like, please give me all the users, where friends it's equal to the user. To, let's say it's less than 100 and name it's equal to Michele or whatever. As you can see, this can work with Facebook APIs, but it's not the same on Instagram. It's not the same on Twitter and whatever. GraphQL offers you the opportunity to kind of standardize all the communications from client to server or even server to server because you can communicate with another server using GraphQL. You can also federate your API, meaning my data can possibly come from a database or from another API or from another different database and I can aggregate the data inside one and only one end point. In fact, as you can see here, we are only hitting one end point and we are passing a query. So we have a formal language for querying our data and we don't have to think about what there is on the back-end. It doesn't really matter because we are using a language which is obstructing for us that complexity. So GraphQL, it's incredibly powerful and we're just scratching the surface of its capabilities but it's really important in my opinion to understand how to use GraphQL those days because it's gaining in popularity and I'm quite sure GraphQL will replace REST one day or another. Just like REST replaces SOAP and so on. So I really hope you will be interested in learning more about GraphQL because it's really, really interesting. I hope I answered your question hopefully.

Okay, we were saying, if the user already exists, just return user already exists. If not, then we can spend. Okay, sorry I was reading your reply Santiago, I'm glad to help. Okay, now that we know that the user doesn't exist we can put that user inside the database. So, first of all, we need to encrypt the password. So const salt. First of all, we want to create the salt. So await the crypt.gen salt. Let's say 10 rounds. Then let's create a hash to password. So await the crypt. Where is it? Hash. Here it is. We pass password and salt. Now we should have a hashed password. Let's see if it works. So let's just return this. Oops, no. I've opened IntelliJ. I didn't want to. Okay, close it. Okay, let's try this. Password is too short. That's correct, I forgot it. Hello world. Internal server error, let's see. The field, oh. Okay, no, sorry. That's my problem on Hasura. Let me fix this. I'm not gonna explain why I just made a little mistake in configuring Hasura. Ah, no, select. I didn't allow people to make aggregate query. And that's on me. I'm sorry. Okay, here is, so as you can see, we've sent hello world, and we got that string in return. If we send it again, a different string. As you can see, at the beginning, we always have the same signature. So please concentrate on the end, on the final part of the hash. So let me send it again. As you can see, the hash is changing every time. So that means it's working fine. Super happy. Okay, now we need to put everything inside the database. We can go back on Hasura API. Now we can say, please help me create a mutation. And we want to insert one user, and we will be inserting email and password. So we will call this insert user. We will need an email, which will be a string. Exclamation point means it's required. Then password. To be a string again. Here we have put email and password. We will be returning let's say the ID for the moment. Okay, let's copy this. Let's create another query. Insert user, we'll pass email. Oops, I'm sorry, no, this is the query. What's going on here? I couldn't copy it. Here it is. Oops! So, okay, we are inserting a user and returning the ID. So let's create the function.

Inserting User and Understanding JWT Tokens

Short description:

We pass an email and password to the async function insertUser. If the user does not exist, we generate a salt, encrypt the password, and insert the user into the database. We return the ID of the newly created user. It's important to note that this manual authentication approach is risky. We will explore a more secure method using Firebase later. Now, let's understand JWT tokens. JWT tokens are signed JSONs encoded in base64 format. The content of a token is visible to anyone, but it's secure. We'll use FastJWT, a library by NearForm, to demonstrate how JWT tokens work and why they are secure.

Async function, insert user. We pass an email, a password, and we say const. As you can see here, we're returning. This is the structure of the object we will be returning from the query. So we can say that we will be returning insert user 1. We can destructure it, say, await GraphQL.request, and insert user as a request, and pass email and password as variables. As you can see here, email, oops, I misspelled password. Then we will be returning insert user 1.id. So it will be returning a string. So const user id. It's equal to await, insert user, email, and hashed. Okay, so we are passing the hashed function here. So if everything went fine, we can say, success, it's true, and we can say, I'm giving you the id of the newly created user. So, are you ready? Should we try send? Wow, it's working. It's working. Let's see what's going on on the backend. User, here it is, and here is the password, which is encrypted. It's really difficult to, you know, to brute-force this. All right, we got it. Let's try again. False, user already exists. And that's correct. Super happy for that. Let me recap everything so I'll get there. But I feel like this is beneficial for everyone. So, this is our API. We are getting the email and password from the request body. If there's no email and there's no password, it's useless for us to proceed. So we just return missing required parameter. Then we want to validate the password. If the password is not valid, it's useless for us to proceed any further. So we just return password is too short in that case, but any validation rules works. Then we will look, if the user already exists inside of our database. If the user exists, we just return an error. The user already exist. So we don't proceed hashing the password, trying to insert inside the database and having a conflict while inserting the user in the database. We don't want to do that. We just ask to the database if the user already exist. If the user does not exist, we generate a salt. We encrypt the password and then we ask, we basically insert our user inside the database using this function. This function will make a GraphQL request for us. We'll insert the user and we return the user ID. So at the end of our chain, we will return success true and the ID of the newly created user. So when we test this, we can try with another email like, we are not validating that email right now. So let's try with a fake one, foo.nearforum.com. Okay, we inserted it and we have an ID in return. If we go on the database, we refresh. We now have two different users with the exact same password, but different hashes, which is extremely important. It's not a simple topic. And I've spent many hours of my life, you know, trying to understand how to make authentication reliable. And the good part is whatever we are doing now, it's something we should never do. I mean, I'm sure you knew the principles of authentication, but I strongly believe you shouldn't, you know, realize handmade authentication because it's, it's really risky again. But we will see later working with Firebase, how to make things a bit easier. We now need to understand JWT tokens. Best part of Hasura besides this has been reading Haskell. Oh boy. Yeah. Haskell is my favorite language, so I do understand your feelings. And of course it has a free tire, but also whatever you're looking at here, it's absolutely free because I'm using the free Heroku database attached to a free Hasura instance on Heroku. So it's completely 100% free. And that's the best part, of course, of the whole workshop I guess. Okay, so we need to understand JWT token. Please rise your hands or give me a thumbs up if you're familiar with JWT tokens. Only two people, three people, okay. Yes, okay, Douglas, awesome. Okay, so I'm gonna explain briefly JWT tokens for all the people that is not familiar with it. We're gonna do that using JWT.io. So JSON Web Tokens are, oh, thank you Santiago. I see you're quite well-informed on the topic. So please let me know if I'm saying something that is not correct because I feel like you'll be able to correct me. That's not, I'm not kidding. Please tell me. So JWT token are basically signed JSONs which are encoded into base 64 format. What does it mean? It means that the content of any token, this is the token on the left, it's visible to anyone. Are you scared of that? You shouldn't. Let me, sorry. Let me, let me go to the workshop repo because I prepared a little demo to show you and I don't want to waste time on it. So we will be using FastJWT, which is a library created by NearForm, the company I work for. I highly suggest you look at this, it's probably the fastest implementation for JWT signing and verification. That's what we do at NearForm. So again, if you're looking for a remote job, please feel free to write to me, and, okay. So let me show you how JWT tokens works and why they are so secure, even if we can see the information they contain. So, I've already created something, so I'll just copy paste them here. We will go in lib, JWT, create an index file. Let it execute. Okay, what's going on here? We create a signer. We will go on that later on. Verify and add the code. And as you can see, we need a secret token. Okay, at the moment, we would be using just the secret thing.

JWT Secret and Token Verification

Short description:

We can use secret as the JWT secret for now. Next.js automatically injects environment variables into Next.js API routes on the server side. Secrets are not available on the client side unless explicitly set as Next_public. Let's create a new route in login.js to demonstrate how JWT works. We can send a fake JWT to the client and decode it using base64. JWT tokens are used to verify user privileges and share non-sensitive information. The token's integrity can be verified using the secret key. JWT tokens are not encrypted, but encoded using base64.

We can use like hello or a super strong password or whatever. As for now, we are just using secret. Okay, we can also do that. That should be better. So we put secret here. We can now go on the dotenv file and create a new dotenv property. Where JWT secret is secret, which is not really secret anymore, but it does the job. So basically, Next.js automatically injects all the environment variable inside any Next.js API route. So whenever you're on the server side, you'll be able to access secrets. Those secrets won't be available on the front end, from the browser, if you want them to be available on the browser, you have to prepend Next underscore public. In that case, the JWT secret will be visible on the client side, never do that. In that case, of course, but it's just telling you that there's that possibility, of course.

Okay. So let's create a new route and I'm showing you how JWT works. So let's go in Auth, index.js, oh, no, sorry, not index, login.js. Let's import design at the moment from lib JWT. Okay, the sign method, as you can see here, will take, sorry, uses decree signer, which takes a secret key and will return a function. So sign right now, it's a function which we, that we can use to create a new token given a JSON input. So what we are gonna do now, is create a simple handler. Let's do that, Request response. And we are just returning rest JSON. And let's say, let's create a fake JWT for a moment, sign. And here we use like admin is true, name Michele Riva, email is michele.riva at nearform.com. So in that case, we are sending a JWT and we are sending it to the client. So if we start the server, first of all, we need to install the package. Let's add FastJWT. Awesome, here it is. Okay, so if we now go on house login, we can just send a request. As you can see, we get a base 64 string in return. So if we take this and we go here to... Oops, wrong folder, okay. If we go here and go like in base64, the code. So first website we find about base64, we paste it, the code. And as you can see, we are able to see the content. But as you can see here, we also have some strange charters. We will see what does it mean. So let's go back on JWT.IO. So basically, we will use JWT token to say, okay, dear user, if you have that token that says that you're an admin, then you are an admin. If you have a JWT token that says that your email is michele.arriva, sorry, michele.arriva at nearform.com, then I assume you are really michele.arriva at nearform.com. But there's a problem. We can take the JWT, put it here, look at everything, and say, okay, let's change this from true to false, okay? That's the problem we want to solve. Which is not a problem at all. And we can test this. If we go here, let's just do that. Let me see if I can rename this to MJS. Oh no. I'll rename this to MJS. And I try to say, as you can see, we just modified the JWT, so it was true. Now it's false. I take this and I say, console log, verifier. So, I'm basically asking, given that secret, I'm asking to verify if that JWT has been modified from, by someone. Okay. So, let's just use, just because I need to use common line right now. Okay. So, if we go here and say, node, lib, JWT. Oh, wow. As you can see here, we have the token signator. It's invalid. Why? Let's try to go here and say, admin is true. But my name is, I don't know, John Doe. And I use that signature, which is random to me. I copy the JWT. So, copy. I go here and replace the old JWT with the one I just created. And we get the narrow. That's because we don't know what the secret is, so we cannot sign the JWT correctly. But if we go here and say secret, which is the correct key for signing our JWT token, then take this. So we copy it. We go here, oops, and paste it. Yes. As you can see now, it's working. So admin true, name is John Doe. This is the email and issued at, so this is the timestamp at the moment I created the JWT token. So, as you can see, inside JWT tokens, we want to share information that shouldn't be private. So don't store passwords. Don't store important tokens. Don't do anything crazy inside JWT tokens. Just say like, I am an admin true or false, my name, my email, nothing sensitive, please. And no one can modify the token without knowing the secret for signing it. So, did you understand why it is so powerful? Please thumb up, as always. Okay, awesome Santiago, Jacob, Basil, Ahmed. Awesome. I'm trying to see the difference between this and the MD5. The MD5 will give you the same result and this one, okay. Yeah, so this is not encrypted. That's the difference. This is not an encryption, this is an encoding. So if you go on Bay64 decode, and say, sorry, yeah, this is Italian. Let's say, hello. Oh, no, sorry.

JWT Encoding and User Validation

Short description:

Let's explore encoding and decoding in JWT. We use Base64 to pass data through HTTP requests without special characters. JWT tokens consist of three parts: the algorithm used to sign the token, the token content, and the signature. We want information to be easy to read but hard to modify, so we don't hide it. The user's email and password are retrieved from the request. We query the database to validate the request and return the necessary data for the JWT token. If no user is found, we respond with an unauthorized status code for security reasons.

Let's go on encode, sorry. If we want to encode hello, this is what we get. And given that, we can decode it and get hello back again. With MD5, you can't revert your hash. You can just brute force it, but you can't revert it to the original phase. And why do we need Bay64, you may ask? That's because we typically pass this through HTTP requests and we don't want special charters to appear. And given that we are using JSON, so the content, as you can see, there are different colors. So all the colors are divided by a point. So we have three different, sorry, two different JSON in the assign network, meaning the first part of our JWT will tell us the algorithm we used to sign the token. The second part will tell us the token content and the last part is the signature. We can choose the algorithm used to sign the token here. And as you can see, sometimes it requires a public key and things gets complicated, so we don't want to do that. So in that case, our signature will be, as you can see here, we basically encode for URI as the header. Then we get a point we encode the payload, so that JSON. And then we encrypt the, sorry, encode the secret. So that's what we're gonna do. We don't want to hide information. So that's the difference between MD5 and JWT. We don't want to hide information. We want the information to be easy to read, but really hard to modify. Unless you know the secret. So that's the power of JWT tokens. And this is what we will save inside a cookie to tell that the current user is logged in correctly. Is it clear enough? Yes, thank you very much. Okay, no problem. No problem, happy to help. So, okay, that's what we are gonna do. So, first of all, we will need to get the user and the password from the, sorry, the email and password from the request. And that's the exact same thing we are doing here. Sorry, here. So if there's no email, there's no password, missing required parameter. Easy peasy lemon squeezy. Then, if we have the email and we have the password, we want to ask our database to tell me, to give me all the information we need to validate that request. So, in that case, we will go on Hazura and say, user, please give me all the users where the email is equal to email, which is a variable. So, get users by email. Email, which is a string. And we will return all the data that we need inside the JWT token. For example, the user ID. Maybe the name, if we have it. The email. And we will need the password, even though we won't be including the password inside the JWT token. Again, never store sensitive data inside a JWT token. So, let's try this. As you can see, this is returning us the ID, name, we don't have a name for now, email, and password. Okay? Also, so let's copy this. Let's go here, let's import GraphQL from graphql-requests. Let's create the query. So, we have graphql. Okay. Email. Get user by email. Awesome. Now, we want to create a function. And also, we want to import. How to complete, please don't do that. Oops. Import GraphQL from lib graphql. Now, we want to create a nice function. Get user by email. So, we pass an email as a permitter. As you can see, we will return an array of users. As you can see, user is a list, it's an array. So, const user equals GraphQL dot request. GraphQL dot request. Get, oops, we use the query we just created, we pass the email. And we return user dot, let's take the first. So given that we only admit one user for one email, we will be getting just the first user we get in return for this query. If we have no users, we will be returning an empty array. Okay, and this will be await. So let's do that. Cons user, it's equal to await. Get user by email. But if, okay, no, sorry, don't return this. Let's just return null. So if we don't have any user, because maybe we just, you know, we just put the wrong email. We've made a typo, whatever. Res status 404. So not found, we couldn't find this user. Invalid email or password. We don't want to say user not found. And there's a reason why. So let me rephrase this. We will use unauthorized. Is there any idea why we don't want to say that we couldn't find the email? No ideas. Security. Great, Santiago. Yeah, that's correct. So imagine, I'm trying to brute force. And I know that there's, yeah, I'm giving clues. That's correct.

User Login and JWT Token Creation

Short description:

When attempting to log in, if the user exists, but the password is incorrect, the server will respond with 'wrong password'. This is done to prevent brute force attacks by not revealing the existence of the user. If the password is correct, a JWT token is created and saved as an HTTP-only cookie. This ensures that the token cannot be accessed by JavaScript on the client-side, providing an extra layer of security.

So I know that, let's say Michele Riva works at NearForms. So I'll try to log in for him. And I try Michele Riva. All attached, without spaces or dots. And the server says, I can't find the user. But then I try Michele dot Riva. And the server says, wrong password. What does it mean? It means that the user exists. The email is correct, but the password is wrong. So as Santiago was saying, we are giving clues. We don't want to let people know when to brute force. So as an extra layer of security, we never say this user exists or it doesn't exist. We just say, wrong email or wrong password. So that's all we are gonna say.

Okay, so if you're here, it means we have a user. So we can create the JWT token. We have the same method. So let's create it. Create the JWT, sign, and we will be put. Oh, I'm sorry. What I'm doing, we need to understand if the password is correct before doing that, I'm really sorry. So let's import ByteCrypt. Okay. So is password correct? It's equal to await, ByteCrypt.compare. And as we were doing before, so we pass the plain text password. So the one passed as a POST request, so password. And then user.password, which is the one we're getting from the database. That will only return true or false. As you can see, it's a promise containing boolean. So true or false. Now, if it's not correct password, we just copy paste this. And again, of course I'm repeating myself. It's not good code, but again it's just for understanding the flow. So invalid email or password. If the password is valid, though, we want to sign the JWT. So JWT it's equal to sign. Sign. And we put the ID. So user.id, email. So user.email. Name, user.name. That's all we need. So res.json. Sorry. Okay. We will do that. We will reply, success, it's equal true in that case. But we will never, never send the JWT token to the client for security reasons. Instead, instead, we will save this as a cookie. That's super important. We will save that as an HTTP only cookie, which means that JavaScript from the browser will never be able to reach that cookie for security reasons again. Because if I create a browser extension, a malicious script, whatever that says, please document.cookies, take them and fetch and push this to my server so I steal the cookies from anyone on that website. That's really bad. Never, never, never save JWT tokens inside client-side cookies, local storage, indexed DB, never do that, never. Please use HTTP only cookies that are designed specifically for that kind of usage. Is it clear? Do you want me to explain this a bit more? Okay, thumbs up from Santiago. I assume that's fine for, okay. Ahmet, thank you. Billy, awesome. So, we need to install one last package here which is called cookie. And as you may guess, it's used for dealing with cookies in JavaScript. So, yeah, let's import it, import cookie from cookie. Now we want to say rest.setHeader because we need to set a cookie. So, setCookie. I guess we should do that this way. I'm blinking out. So, let me see for a moment. I made some tests before joining the workshop. So, let me see. I'm quite sure we did it this way. Just want to make sure. SetCookie, perfect. Cookie.serialize. We need to give a name. So, we can call it authorization. We can call it foo, whatever. This is not really important. Oops. Then, the value for the cookie, which must be a string. So, we pass the JWT token. And then some options, which are incredibly important. For example, HTTP only. True. Domain, we can say, okay, this cookie will be only valid on, let's say, amazon.com. Or every single domain inside amazon.com. For example, beta.amazon, I don't know, whatever. Staging.amazon, we can do that. So, third level domains can be included here, and also wildcard domains. We won't do that for the moment. But we want to say expires.

Attaching Login Part to Front End

Short description:

We successfully created a login and registration method for our Next.js app. The good is that we have complete control over the authentication flow and no dependency on external services. The bad is that our code may not be as beautiful as that written by professionals in the authentication industry. The ugly truth is that companies investing billions in authentication security provide more reliable solutions. Let's proceed to attach the login part to the front end and discuss the options for the next hour. We can either integrate Firebase or show you how to deal with the JWT token on the client side. Your preference? Thumbs up for Firebase, thumbs up for the client-side JWT token. Let's go with the client-side JWT token integration. While it's important to understand the risks of implementing authentication from scratch, relying on professional external services is recommended for production usage. Now, let's move on to attaching the login part to the front end by using the useState hook from React.

So, after how much time do we want this to expire? And this is the property we typically set when the user checks, please remember me. So we can say expires, if I remember correctly it's in seconds. Let me see from... Also now it's max age. So, instead of saying please expire on that date, we will say this cookie will be valid for 60 seconds times 60 minutes times seven days. So this is how long the cookie will remain. And believe it or not, we did it. So let's try this.

So my email was, we said seven hours, Douglas you might be right, it's becoming late and I'm starting to blanking out. So it might be right, it might be correct. Okay so my email, I registered with the email Michele dot Riva, at near form dot com. My password was, hello world. Are you ready? Let's try this. We couldn't connect to the server because, I didn't start the server of course. Awesome. Oh, wow, we did it. Let's try, okay, here is the cookie. So if we now take this, and go here, as you can see, this is correct. This is my ID. This is my email. I don't have a name in the database. So we did it. Awesome. So we just created a login, and I see the party reactions, great. So we just created a registration and login method for our Next.js app from scratch. Before we move on, I would like to ask you, what are in your thoughts, the good, the bad, and the ugly of that solution? So anyone has any idea? Please, feel free to use your microphone. Don't worry. I see Santiago saying that needs to drop off. Thank you a lot, Santiago. Has been a real pleasure. I see you're really interested in this, and you have some expertise, of course, because with conversations, make sure to connect on Twitter. I'd be glad to explain if you need some explanation. Have a nice rest of the day. And, okay, Oscar, you were saying something? No, I wasn't saying, but I can say the bad is there's so many details, and if you make one little, it's a lot of, you have to know quite a bit to do this, and you have to be sure. Exactly. I agree. That's for me. The good is you will understand it, and then you master the other thing. So, anyway, so that's... But, what I like, what I see is, like you mention, never to put anything in local storage or in the CV, and that, so use the HDB only cookie, right? Yeah. That's what you will use if you have an application that you want to have a session, for example. Yeah. So let's do that. I'm gonna give you my ideas on the good, bad and ugly. Then I'd like to propose you how to proceed, because we have one more hour and... Okay, now let's do that. I have a proposal for you. We have one more hour. We can decide two options. One, we move on understanding how to integrate Firebase. Two, we attach this authentication mechanism to the front-end together, I show you how to do that, and how to deal with the data we just created, because how do you access the JWT token if it's not available on the client side? So there are resources online explaining that, but I'd like to show you. So personally, I'd like to proceed working on this one, and I will give you some information, generic information about Firebase Auth0 that you can find online. So I'd like to ask you, what do you want me to proceed on? Please turn your thumbs up if you want me to go on Firebase. You see, I know it's the visitor asking for, okay, option two. Okay, so let me do the opposite. Please thumbs up if you want me to work on option two. So integrate everything together, make it work, and then give you some information on Firebase, generically. Awesome. Yeah, yeah. Okay, let's do that. Great. We have one hour. Let's do that in one hour. We went really far in just two hours. So that's really, really great. So in my opinion, the good is we have complete control over the whole authentication flow. Having the whole control of the whole chain is a blessing in a curse, meaning we perfectly know whatever happens. So if there's something not working, we may know where to put our hands to fix it. We don't have any dependency on external services. So this is great. We do understand how things work, which is really, really fine. The bad is our code won't be as beautiful as the one written by professionals working in the authentication industry. So that's something to consider. We have to behave in a way that whatever we do is secure. We have to understand the risks of implementing authentication from scratch. So I find this to be interesting as long as we do that for learning purposes, not for production usage. The ugly is that there are companies investing billions in making authentication secure. And I wish you'll understand that we don't want to use our own authentication mechanism. I'm showing you how authentication works at a high level, but there are companies doing that professionally for a very long time, and they do something that we wouldn't be able to replicate alone. So please rely on professional external services when you have to deal with authentication. That's really, really important. Okay, so let's move on. Let's try to attach the login part to the front end. Okay. So we have our API. Let's go in login. So as you can see, we have a simple form. Let's just use our useState from React.

Handling Form Submission and API Fetch

Short description:

We have a simple form with useState from React. We handle the email and password inputs and console.log their values. We fetch the API for login and handle success and error responses. We encounter a missing required parameter error, which we debug and resolve by stringifying the JSON body.

So as you can see, we have a simple form. Let's just use our useState from React. So if... Oh no, what am I doing? Say email, setEmail. The same for the password. Now here we say... Okay, the value is... Email. Here is password. On change we got an event. Let's call it e. And we want to setEmail... Sorry, etargetValue. In that case, setPassword of course. And we can try to debug this by console.log Email password. So if we go here, we go in login, as you can see it starts with empty, so ciao, which is hello in Italian and hello. So it's working pretty well.

Once we are done, we want to submit the form. So we can say, button here, can go on a new line and say on click, handle login. So we can create a function, handle login, which will fetch the API we just created. So fetch, API. Where is it? I can't remember. Auth, perfect. Login. And then we need to pass a couple of options, like method, which is post, as we've seen. Body, which is a JSON we need to stringify. So we're going to pass email and password. Then we can do that. We can import user router from next router. So we can use the router hooks and say, okay, if everything went well, we can say, router.push to profile. So we can see the profile page finally. If there's an error, for example, user name or passwords are wrong. That's the key is for an error. For the moment, let's just log it. We are not really concentrating. We could show a banner, we could show an error message, whatever. Let's try this. So kehle.riva at neoform.com. Let's try with a wrong one. It's doing anything. Login.js. Oh no, what's going on? Hmm. Let me refresh for a moment. Maybe it was cached. Oh, okay. It's not working properly. Let me show you why. Sorry. If you go here, you see preview, missing required parameters. Email and password. Okay, let's see why. So if success is false, because we are entering here. So we can say, data. Return data.json. Then we can do that. Sorry, if success router.push to profile. Okay, so we always return success, which can be either true or false. But in that case, I'm putting random data. Okay, awesome. We are just, we are just, you know, getting an error message from the server. We could show something here, not important at the moment. Missing required parameter, why? Okay, that's, that's something I'd like to understand. Let me see for a moment, like blinking out. So fetch, host. I know I'm doing something wrong here. If you have any idea, please tell me. We should say, okay, JSON string if I, for, okay, no, it should be correct, actually. Let's see on the server what's going on. So. I just want to see the request body. Let's try to debug. So of course, no, that should be correct. Okay, so we have a problem here. It says missing required parameter. So either email or password right now are one of them it's false. Let's see why. Whoa, they are undefined. Oh, maybe I have to, I'm sorry. I'm really sorry. That's right. But sure. That's why. Awesome. Yeah. Okay. Sorry. My bad, my bad. We have to stringify I couldn't remember this. Okay, great. Okay.

Fixing Cookie Saving Issue

Short description:

Now, let's go and see the cookies. We should see the out cookie to be set. We are going to fix this in a moment. Let's install Next Iron Session, a package that manages cookies for us. We wrap the entire handler with the iron session handler and pass the cookie settings. We can access the session parameter and save the session using a method. Let's try and see if it works.

So now it should be working fine. So, okay, of course, we are getting an error. As you can see unauthorized, which is correct because I'm putting random data here. So wrong email and password. So now I'm putting correct ones. The password is Hello World. Yeah, we did it. So we are logged in. That's awesome. How can we ensure that we are really logged in? Let's go and see the cookies. Let's try to refresh. Okay, it seems like we are not saving, oh no, let me maybe, the browser extension maybe has no access. Let's try to see here. In application, cookies, okay, it looks like we are not saving. This is another session. So, we should see the out cookie to be set. I'm probably using the wrong keyword here. So let me see for a moment, because I was sure these were working pretty well. So, cookie.j.npm, wrong package. Okay, let me see for a moment. No, that should be correct. Set header, let me copy paste this. Yeah, it's correct. Set cookie, max age, let me copy this. So, this is one week. Of course, as Douglas was saying, I forgot to multiply times 24. Okay, no, that should be working just fine. Let's see what's going on here. Let's try again. So let me hard refresh and go here. Hello, World. Okay, I don't know why, it's not showing up here. Okay, you know what? We are gonna fix this in a moment. This is something I wanted to show you on Firebase, but we are gonna implement this right now because I don't want to waste any time. But it's working in the exact same way. I don't know if any one of you is familiar with Iron Session. Is there anyone familiar with that? Thumbs up in the case. Okay, I guess this is a no. So, Iron Session, it's basically a Session manager which uses cookies underneath and encrypts them. So, extra layer of security. We can also store sensitive data inside cookies because it gets encrypted. And there is an awesome package called Next Iron Session. Oh, okay, they revriem. Yeah, okay, so let's go here. Let's install this. So they basically manage cookies for us. Okay, we got it. Now this is an example with Next.js. So it's pretty, it's an hour case. So let's go here and say, with iron session. Okay. And we basically want to do that. So we go in lib, we create an out folder, an index file, and we create, so we do want to export const cookie settings. Which will be an object. So cookie name that we will be calling out, a password that will be process, and env. We can use whatever we want basically, like the JWT secret or whatever, let's use this for a moment. Secure, we can use secure in production only, so it's easier for us to debug. So now, we can import it, like import, cookie settings. From. I changed my keyboard to the English layout from the Italian one, so, it's really difficult for me to type correctly right now. Out, awesome. So, as you can see, it asks us to wrap the entire handler. So, we can do that. Const, oh, sorry, as in function handler, and we can do that. Export default with iron session API route, as you can see here, handler. And we also want to pass the configuration as a second parameter. So, we say, please, these API routes wrap it inside the iron session handler, and also pass the cookie settings, so that it creates and reads encrypted cookies. So, what we do now is to go in... And, okay, we will get a new property inside the request. So, we can set the... We can say, rest.session. We can finally access the session parameter, rest session, as you can see, user, for example. And we can say, a session.jwt, it's equal to JWT itself. Okay. And then we have to use this method to save the session. Let's try and see if it works. Go back here, login, let's open here for... Oh, yeah. Yarn dev. Let's refresh. Let's try again. Okay, oh, yeah, I know why. Bad usage. Password must be at least 32 characters long. Yeah, that's cool. As you can see here, we're basically passing the JWT secret. Let's write a very random one, which, because it wasn't secure enough and iron session prevents us from using a secure password, which is really, really fine. Really good. So let's try again. Oops.

Using Iron Session for Cookie Management

Short description:

We encountered an error while trying to manually set a cookie, so we switched to using Iron Session. Iron Session saves the session as a cookie and encrypts the data for an extra layer of security. The cookie is saved on the browser and hidden from JavaScript. The expiration date of the cookie allows access until the specified date. However, we need to protect the routes and prevent access without the cookie. To do this, we will create a hook called useAuth, which will handle the loading state, user state, and logged-in status. We will fetch the session API to retrieve the user data and set the user state.

Okay, we got another error. Let's see. Okay, not okay. What's going on here? I'm really sorry about that, but let's see. Oh, I got it. Okay, as you can see, I'm putting this to rest. We need to put it to the request, not to the response. So eventually we can try again. Sorry, I wasn't expecting to do this.

Okay, so that's what we got. As you can see here, we have the auth cookie, which is HTTP only. So if we go here and say document.cookie, as you can see, it's empty. So JavaScript cannot access this cookie. This is really important. And this is encrypted. So if we go here on basis 64 decode, as you can see, it's completely useless. So it's an extra step of security, not really needed. If you're using JWT tokens, still fine. Still fine if you want an extra layer of security. So is it clear why are we using Iron Session? Do you want me to repeat quickly?

You are using Iron Session to save the cookie in the session, but why do you think you try to do it by scratch and it wasn't doing it? So you are using Iron Session, right? Yeah. Okay, I see Ahmet asking for clarifications. So I'll give you some of course. The idea is that I was trying to manually set a cookie and maybe I was... I don't know, I made some mistakes and I didn't want to waste time. So whatever we were doing by hand, like response.setHeader, so we were trying to say, okay, dear browser, I'm sending you a response, which includes a new cookie. So the browser should take this cookie and save it HTTP only, so only the servers will be able to access this cookie. There was some kind of error that I wasn't expecting, so instead of trying to debug and waste some time, I wanted to use the iron session, which does the exact same thing, and I'm telling this specifically for Hamit, which asked for clarification, does the exact same thing. So it basically takes a parameter here that was not shown in the code, a parameter here, so it creates a new property inside the request object, it creates the property session, and say, okay, inside that object, we put the JWT property. So we will end up having request that it's equal to session, which is an object that has JWT that has the JWT string. Then we say, okay, now save it. And by save it, we mean save it as a cookie because iron session basically saves the session as a cookie just like we did, just like we did, but correctly, because it's clear that I made some mistakes here. And also it encrypts the data. Which is an extra layer of security. We don't always need it. But it does it for us for free. So I guess it's fine. Is it more clear? Do you need more explanation?

Save it where? In the server? Nope, it saves it on the browser. On the browser, okay. Yeah, but it tells the browser to avoid access to this cookie to JavaScript. So on JavaScript, if we say document.cookie, as you can see, we are not able to see that cookie. Because we are basically telling the browser to hide this from JavaScript. And it is real, so anytime you sign in as that person, then you will see that cookie, is that right? Or how is it going to happen? Excuse me, couldn't understand. Yeah, that cookie is also, when you come back later on, you should be able to. Oh yeah, yeah. Yeah, as you can see, the expiration is for the 9th of March. Okay. So yeah, until that date, we will be able to access this cookie. Okay. Okay. And great. So now there's a problem. We are logged in, but if I delete the cookie, I'm still able to access this page. So it's not really useful. We now need to protect these routes, right? So let's do that. We will need to, oops, it canceled. We will need to create unhook. And it will be pretty easy, actually. We can go in lib, use... No, let's go on auth. Hooks.js, and we can create like import, use effect from react. I don't know why it's auto-completing like that, export. Let's call it function. Use auth. So let's import, use state. We will need a couple of states here. For example, we will need loading, setloading. Use state true. So by default, whenever we use this hook, we start to load a loader. And we will see why in a minute. User, set user. By default it's now... So, and I feel like, yeah, we can use error if we want to put any error. Don't do that for the moment. We will return loading, set loading, sorry, any user. We will also get a property called logged in, which, if it's not loading and we have a user, so that will be an object. So object, keys, user, length. That's the only way we have to control if the object is not empty. The object is not empty and it's not loading. That means that we have the user. As soon as we load on the client-side, we say, useEffect. Okay. So, useEffect. Fetch. And we will need to create a new API. Api, auth, get. Session. Then, then, we'll get a response. REST.json. Then, Set user. REST.user.

Creating the Get Session API Route

Short description:

We create a new API route called get session to retrieve the session and send it back as JSON. We decode the JWT and return it as a session JSON object. Let's test the hook now.

Let's do that. Then, oh, sorry. Catch. If we have any error for now, let's just console log. Finally. So we don't really care at this point if it's succeeded or failed, but we will stop the loading function. So set loading. False. So it's not loading anymore.

So we will need to create a new API for getting the session and giving it to the client. And we will do that by going into pages, auth and creating the API route. So get session. It will be quite similar to the register one, so I'm just copy pasting it. But it will, oh, sorry. Not, I mean, the login one. That will be way easier. So we can delete all of this. We just need the next item session.

Okay, so now if we go here, let's try to login from, oh, what's going on? Why it's not logging on here? I don't know, nevermind, we left a comma. Where did we left the comma? It hooks. I think that's a use effect. Oh, you're right, thank you. I don't think that's the reason why, isn't giving me any useful explanation. Oh yeah, I know why. Oh yeah, here's why. We are parsing, we should do that. Type of req body string json parse req body. Otherwise, let's just return req body. That's not the reason why. OK, yeah, now that, it's because I'm stupid. OK, now it's working. Yeah, and as you can see, we have the cookie. OK, great. So I just want to test it. I did that just to save a cookie inside Insomnia, which is the client I'm using right now. So now if I go on here, we got return. Let's try with res-json-session. And we can try to put request.session.jwt. Let's see what we get. So get Session. Let's see. Okay. We have an error. Oh yeah, I didn't import the cookie settings. That's correct. Let's try now. Okay. Let me see how do, because they changed the library right now see if we can do this. Right session. Oh, okay. No, that should be correct. Let's try this. Request session. I'm not sure Insomnia. It's able to. Oh yeah. That's why it didn't save the cookie. Okay. No, we will, we will debug this in another way. Maybe we can just use this but we, oh no, of course we can't. Okay. Okay. No, no problem. Sorry. Sorry. So we get the cookie like this const request, say cookie. So let's call it the JWT. So here we get the JWT, right? We also want to decode it. So, I can't remember the name so we can just import it as follows. lib JWT. So now we can see the exports. Oh no, why is not showing up? Let's go here. The code. Okay. So, we get the JWT stored inside the session. We now get, now say, constant, decoded, is equal to the code JWT. We then send the session back this way. So, I can't remember. We call it res.user. Now let's call it session. Okay. So we're basically saying there is a session inside of our requests, which is called JWT. Oh, hope to see you soon Basil. It has been a pleasure. Hope you enjoyed the workshop. And yeah, let's connect on Twitter if you, if you have any question, of course. So we're saying, Oh, thank you. Let's take this JWT, decode it, and send it back as a, as a JSON. So we can try. We can try to use this hook now.

Creating Wrapper Components and Testing Routes

Short description:

We create a wrapper component called out wrapper that takes a children component. If the user is logged in, the children component is returned. If not, the router pushes to a 404 page. The layout wrapper is used to create an alias for the out wrapper. The router's as path property is used to determine the current route. If it starts with 'profile', the layout wrapper and component are returned. Otherwise, only the layout wrapper and component are returned. The code is tested and working fine. The login functionality is also tested, but there may be an issue. The speaker thanks the audience for attending the workshop and invites them to connect on social media.

If we go, for example, in components, we can create a wrapper, an out wrapper, export, default, out wrapper, which takes a children component and does the following, imports, use out hook from leap, out, and here we are. Okay, now, it also uses, no, it doesn't need to. We can say return. Let's use this, const, loading is log in. Use out. So, what we do is, if is loading, we can return a loader. Okay. If the user is logged in, and here we should pass a couple of props. Let's say we just passed children. So we only show this page if under authentication. So, if it's logged in, let's return props.children. Okay. So, if it's not logged in, you can use the following. Import user router from next router. And here we say const router equal to user router. And now we say, if it's not logged in, just router.push to 404. So, rout not found. And return now. So, we can also do the following. We can return, but maybe we will do that later, props.children, and we can also pass user as a prop. So, we can, as you can see, we are returning user here. So, we can return user, so that every single part of our application that is wrapped inside the logged in wrapper will have a user prop by default. That could be working, I'm not sure, but we will try. We have half of an hour. We will try to do that. Let me drink some water and we will do that. Let's do that. Okay, so let's go now in app.js. Okay, here we can import, again, the use router hook. We also import the wrapper, and we save. Let's try to route our.aspath. This is the property we want to test. So if we go here, let's refresh. As you can see, profile. Profile change password. Products and the product ID, right. So basically we want to say if we want to create an alias like, let's call it layout wrapper. so we just return whatever we have here. But here we pass props children. So now we can basically say, if router dot as path starts with profile. So if the current routes starts with profile, we want to return out wrapper, layout wrapper and component. otherwise we would be returning just the layout wrapper and the component itself. So we basically moved a couple of things around. Let's try and see if it works. Okay, don't worry about that, but as you can see, it's working pretty fine. Let me delete my cookies. Awesome, I already deleted them. So if we now go back and let's try the new fixes. To go on log in, it should be fine, but if I go on profile... Oh, use out is not a function. Okay, let's see what's going on here. Ah, author wrapper. So it complains with use out. Oops, what did I do? Oh, yeah. Hooks. Sorry, I'm putting it the wrong file. Awesome. It's working fine, as you can see. So, what we do is, you can navigate any route, but if the route name starts with profile, as you can see, it will push you into a 404 page if you're not logged in. So now, you can go on login and say michele.rivaatnearform.com. Hello, world. And I'm not sure it's working. Let's hope for it. But let's try. No, it's not working. Let's see why. Okay. Okay, let's try understand why. Now we can try to debug. But we are almost there. Okay. So we are here. Let's see on the network what's going on. This is the hook. I fear we didn't call this one. So let's see what's going on here. Oh, thank you, Vitor. I hope you enjoyed the workshop. Let's connect on Twitter or LinkedIn so we can continue the conversation. I hope you enjoyed it. Thank you for being here. Let's try to debug. So, okay. I fear there is a problem. Give me one very second. I need to check one thing which is private but I just want to make sure it's working properly. As you can see the hook is continuing to code itself. I just want to make sure I did the right thing here. So, sorry. Give me one second.

Troubleshooting Session and Server-Side Rendering

Short description:

We encountered an error while trying to access the session. The Iron Session seems to have some problems saving the session properly. However, the main point is understanding how we manage authentication with the out wrapper. It calls the server to decode the cookies and send the necessary content to show the page to the user without revealing the cookie content. We discussed the potential issue of server-side rendering protected pages and concluded that it is unnecessary and inefficient. Instead, we should prefer static side generation and client-side rendering for dynamic data. Server-side rendering should only be used when content needs to be indexed by search engines. The goal is to hide as much as possible until strictly needed.

No, no. Yeah, it should be working fine. Okay, now let's do that. First of all, no. If we are not logged in, let's go to the login. So okay. So that we can see what's going on here. So this is the get session. We have some problems with the get session. As you can see, this is the cookie we're passing and get session API is going into an error. The token must be a string or a buffer. Okay, I guess we are having some problems where we, let's go on pages, APIs, get session. Okay, I guess this is undefined. So I'd really love to see rack.session and I'm sorry I'm taking too much time on this but I wasn't expecting to be working on this one I wasn't prepared but I see you all look quite interested in this. I have to, Comcast won't send my message and this is to the DRA. What message? If you can mute your microphone, really sorry. And okay, so as you can see yeah, we can't assess the session. Let's see why. I feel like there's no reason why this shouldn't be working. We can do that. Give me one second here. I fear that we can't save the JWT inside. So let's just put this. So let's try avoiding putting a JWT inside the session. Session, awesome, get session at this point, session JWT. This point, that should be it. Let's try. Let me delete my cookies. Log in. Okay, so we got our authentication and awesome, that's a decent error, I guess. Let's see if we can see. Okay, let's see if we are able to access the request. No, I guess we can't. So it's logged in, I wanna see user. But actually, oh, so it returns an empty user. I fear we have some problems with the Iron Session. So as you can see, it's undefined. I don't know why it's not saving the session properly. As you can see, we are basically doing whatever they ask for. I don't want to waste time on this. So it's important to me that you get the point of what we did here with the out wrapper. So this is where we manage the authentication. So we basically say, if that route is protected with authentication, we call the server, because we don't have access to the cookies. We call the server and say, okay, server, please decode the cookies, send the content to me, so that I can show the page content to the user without having to show him the cookie content itself. So just send me the minimum data you need. So while it's loading, of course, we will be loading. If the user is logged in, show the page. If it's not logged in, let's push the user to log in. Now you may be thinking, that provides us from server-side rendering authorization protected pages, right? Do you think that's a problem? Open question. Thumbs up if you think that this can be a problem. I guess that's a no. Okay, Douglas, you say that might be a problem. Why can it be a problem? That's my second question. Given that search engines, let me stop sharing because I feel we are running out of time. But given that search engines won't be indexing private content, and given that server-side rendering it's really expensive on the server, and it's really slow, especially with the React, we don't want to serve private pages using server-side rendering because all the content we need, it can be rendered on the client side once we are sure, once we ensure that the user is logged in properly. So there's no reason why we may want to server-side render private routes. From this workshop, I wish you can take home a couple of learnings. First one, avoid server-side rendering whenever you can. Even though Next.js is built for server-side rendering React, I'd like you to prefer static side generation and incremental static regeneration when possible. I prefer client-side rendering for dynamic data and use server-side rendering only when extremely needed. If it's not needed, please avoid it. And you only need server-side rendering when you have content that must be indexed by Google, by Bing, and whatever. And I can't find many reasons why we should server-side rendering, but that's for another workshop, of course. So it's another problem. That's what I want you to understand. We want to hide as much as possible until strictly needed. So that's another learning, in my opinion, for managing authentication in Next.js.

Watch more workshops on topic

React Summit 2022React Summit 2022
173 min
Build a Headless WordPress App with Next.js and WPGraphQL
WorkshopFree
In this workshop, you’ll learn how to build a Next.js app that uses Apollo Client to fetch data from a headless WordPress backend and use it to render the pages of your app. You’ll learn when you should consider a headless WordPress architecture, how to turn a WordPress backend into a GraphQL server, how to compose queries using the GraphiQL IDE, how to colocate GraphQL fragments with your components, and more.
React Day Berlin 2022React Day Berlin 2022
53 min
Next.js 13: Data Fetching Strategies
WorkshopFree
- Introduction
- Prerequisites for the workshop
- Fetching strategies: fundamentals
- Fetching strategies – hands-on: fetch API, cache (static VS dynamic), revalidate, suspense (parallel data fetching)
- Test your build and serve it on Vercel
- Future: Server components VS Client components
- Workshop easter egg (unrelated to the topic, calling out accessibility)
- Wrapping up
Node Congress 2023Node Congress 2023
109 min
Node.js Masterclass
Workshop
Have you ever struggled with designing and structuring your Node.js applications? Building applications that are well organised, testable and extendable is not always easy. It can often turn out to be a lot more complicated than you expect it to be. In this live event Matteo will show you how he builds Node.js applications from scratch. You’ll learn how he approaches application design, and the philosophies that he applies to create modular, maintainable and effective applications.
Level
: intermediate
React Summit 2023React Summit 2023
56 min
0 to Auth in an hour with ReactJS
WorkshopFree
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool. There are multiple alternatives that are much better than passwords to identify and authenticate your users - including SSO, SAML, OAuth, Magic Links, One-Time Passwords, and Authenticator Apps.
While addressing security aspects and avoiding common pitfalls, we will enhance a full-stack JS application (Node.js backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:
- User authentication - Managing user interactions, returning session / refresh JWTs
- Session management and validation - Storing the session securely for subsequent client requests, validating / refreshing sessions
- Basic Authorization - extracting and validating claims from the session token JWT and handling authorization in backend flows
At the end of the workshop, we will also touch other approaches of authentication implementation with Descope - using frontend or backend SDKs.
Node Congress 2023Node Congress 2023
63 min
0 to Auth in an Hour Using NodeJS SDK
WorkshopFree
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool.
We will enhance a full-stack JS application (Node.JS backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:
- User authentication - Managing user interactions, returning session / refresh JWTs
- Session management and validation - Storing the session for subsequent client requests, validating / refreshing sessions
At the end of the workshop, we will also touch on another approach to code authentication using frontend Descope Flows (drag-and-drop workflows), while keeping only session validation in the backend. With this, we will also show how easy it is to enable biometrics and other passwordless authentication methods.
Table of contents
- A quick intro to core authentication concepts
- Coding
- Why passwordless matters
Prerequisites
- IDE for your choice
- Node 18 or higher
JSNation Live 2021JSNation Live 2021
156 min
Building a Hyper Fast Web Server with Deno
WorkshopFree
Deno 1.9 introduced a new web server API that takes advantage of Hyper, a fast and correct HTTP implementation for Rust. Using this API instead of the std/http implementation increases performance and provides support for HTTP2. In this workshop, learn how to create a web server utilizing Hyper under the hood and boost the performance for your web apps.


Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.
In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.
Node Congress 2022Node Congress 2022
26 min
It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Do you know what’s really going on in your node_modules folder? Software supply chain attacks have exploded over the past 12 months and they’re only accelerating in 2022 and beyond. We’ll dive into examples of recent supply chain attacks and what concrete steps you can take to protect your team from this emerging threat.
You can check the slides for Feross' talk
here
.


React Summit 2023React Summit 2023
27 min
The New Next.js App Router
Next.js 13.4 recently released the stable version of the "App Router" – a transformative shift for the core of the framework. In this talk, I'll share why we made this change, the key concepts to know, and why I'm excited about the future of React.
Node Congress 2022Node Congress 2022
34 min
Out of the Box Node.js Diagnostics
In the early years of Node.js, diagnostics and debugging were considerable pain points. Modern versions of Node have improved considerably in these areas. Features like async stack traces, heap snapshots, and CPU profiling no longer require third party modules or modifications to application source code. This talk explores the various diagnostic features that have recently been built into Node.
You can check the slides for Colin's talk
here
.
 


JSNation 2023JSNation 2023
30 min
The State of Passwordless Auth on the Web
Can we get rid of passwords yet? They make for a poor user experience and users are notoriously bad with them. The advent of WebAuthn has brought a passwordless world closer, but where do we really stand?
In this talk we'll explore the current user experience of WebAuthn and the requirements a user has to fulfill for them to authenticate without a password. We'll also explore the fallbacks and safeguards we can use to make the password experience better and more secure. By the end of the session you'll have a vision for how authentication could look in the future and a blueprint for how to build the best auth experience today.