Handling user roles is not that simple on Next.js using Firebase.

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Firebase provides you with the necessary tools to easily authenticate your users using your preferred front-end Library without the need of having a backend system however if you are using nextjs for its server side capabilities then you might have noticed that it's not that easy to integrate it with Firebase authentication sure you could do Dynamic page layouts on the client side but that would just go against everything server side rendering is all about what I want is to be able to handle authentication not only on the client side but also on the server side not only that but I also want to be able to handle it on the page routing system as well as the API routing system and I want even more I want to be able to create roles for each user and to dynamically send pages from the server to the client based on the role of the user and even fetch data tailored specifically to that user from the API and it doesn't stop there I want to be able to do all of this inside the Firebase emulators so we can test everything locally and not have the fear of handling live data so by the end of this video you will have something like this you can login with Google have different roles for different users restricted Pages based on user Ro and dynamic data also based on user Ro don't forget that if you want to follow along you can always download the code from my website I'll leave the link in the description okay guys so to begin with we are going to create firstly the nextjs project and to do that let's go ahead and type npx create next app and we are going to use the 13 version and more specifically the 13.56 so we can make sure that everything goes okay and smoothly we have the same version so let's go ahead and install it we'll just say that we want to install it on the current directory and everything else it's going to be default so let's just go ahead and click everything so now that we have our project installed the next thing we need is to go to the Firebase website okay so in the website what we can do is click here on the get started and let's just add a new project and let's just name it so nextjs Firebase off there you go and continue and now it's giv me the option to enable analytics we are going to say no for that we won't be negating it we're just going to tackle the authentication part okay now to finish our project let's go ahead and click on the web version just give it the random name let's go again with nextjs Firebase oh go with that register okay perfect and now that we have this let's just continue to the console and now let's say that we want to add the authentication so there it is get started and for now let's just go with the Google provider because it's easier to implement and we just want to check how the authentication Works in both the nextjs and Firebase so let's just go with that okay that is working and now we just need to add the fire store so let's go and click on the fire store here create the database let's just go with the default location that's okay and let's say already that we are going on production mode because on the Firebase rules we are going to set everything to false because we are going to be the ones in control of the data meaning that instead of calling the data from the client and making the rules accordingly so we have protected data we are actually going to implement our own protection on our nextjs server so we are going to put everything to false so enable it okay perfect and that's it so now we just only need to install Firebase CLI on our local machine so in order to do that let's go back to our terminal and we are going to type npm install minus G4 Global installation Firebase tools so go ahead okay perfect so not to install the Firebase project on our next JS project project what we have to do is type Firebase in it this will give us a few options and you can change the options with the arrow keys and select them with the space bar and for this project we are going to use the fire star the functions and also the emulators press enter and let's select an existing project so now simply select the project we've just created let's say we want to use the default rules yes also default so just click enter for the functions we are going to use typescript so go ahead and select it and yes we like to enable yes length we can install the dependencies later so go ahead and click no and for the emulator we are going to need the authentication the functions and fire store for the ports just leave everything to default so click enter and yes we would like to enable the UI just go ahead and click enter on every everything else and you're basically done okay so now just to have everything organized let's go ahead and create a new folder and call it Firebase and go ahead and drag the functions inside that new folder now just go to the Firebase do Json and instead of having the source for the functions on the functions path we are going to say it's on the Firebase functions lastly let's go to the package.json and on the scripts let's add a new one call it emulators and the command will be Firebase emulators start okay perfect so now that's done the only thing you need to put everything up and running is yarn Dev to start the development site on the nextjs and I'll just open another console and type yarn emulators to start the Firebase emulators okay so as you can see in the console we have here the URL for our emulators and this will bring up our dashboard for the authentication fir store and every other emulator that we enabled in our project go ahead and also open the nextjs project okay perfect so now we have the nextjs client and the Firebase emulator with the fire store so we can now start developing and thinkering a little bit with the data okay so let's start by creating some pages but before that let's go to the app folder and on the main layouts we are just going to add a new main tag with a little bit of styling so we can have everything centered on the screen and with uh a little bit of a beautiful styling okay now in the main page let's go ahead and select everything from it and simply delete it and add a simple header saying home page okay like so you can delete this let's also just have a little bit of styling on the header and because I don't like the default styl in that nextjs gives to us we are going to go to the global and simply select everything besides the tailwind and delete it there you go and now let's just create our Pages for each of our users so the first one would be the user one the next page would be the pro user and the final one would be the administrator for each one let's create a page. TSX file and for now each page will be simply a header with the name of the current page now go ahead and copy the page file let's do the same for the pro and the admin and it's at each one let's just change the names for pro also here and finally for the administrator so now in our application we can see that on the current URL we are on the homepage if we type in user we now get redirected to the user page and the same for the pro and the admin so now what we need is an navigation bar so the user can effectively change Pages without going to the URL so let's go ahead and create a components folder and inside let's create a new file call it navb bar. TSX inside let's create our component and it will simply be two divs with some stylings don't worry if you don't know the styles again if you want you can follow along the code if you go to my website and don't forget that the nav bar will be rendered on the client so let's go ahead and import the use client Direct and inside the container we are going to put four links one for each of the pages so the first one for the homepage let's go ahead and import it from next link the next one for the user page for the pro and finally for the admin page now we don't want to have always the same buttons we want to render them conditionally so what we can do is on the top of our component let's go ahead and use the use path name hook from next navigation and create three variables each one to know if we are on the correspondent page so now what we can do is simply go to the links and render them conditionally based on the current user page again for the pro and for the admin for the homepage we just want to render it if we are in either of those three pages finally let's just use our component by going into the layout and on top of of the children let's go ahead and render it and import it from our components okay perfect so as you see we now have a user navigation bar and it's rendered on the client and if you click on it it goes to the correct page and just renders the correct pths the user is able to go okay so now to fetch our data what we could do is only use Firebase directly from the client but that's against the purpose of this video so what we are going to do is do an abstraction and simply get the data from our API routes system so let's start by creating a new folder inside the app folder and call it API inside we're going to create another folder and call it items this will be the main endpoint to get our items to make this an official nextjs endpoint we are going to create a new file and we have to call it route. TS okay so in order to create a get endpoint on this pth the way it works in nextjs is by creating a new function and call it get let's go ahead and simply wrap everything inside in a TR catch block so if anything goes wrong we simply return a response thing internal error let's start by creating the type for our items so go ahead and Export a type let's call it item and this will have three things so the first one it's the ID which will be a string then it will have a title and finally it will have an access type which will be of the type of item access this Tye will be the one responsible for saying which user role has the access for that item so let's go ahead and create it it will be an inum let's call it item access and it will have the public the user the pro and the admin now if our database in this case the fire store doesn't have any items for now we are going to say that it will have these default items so again this is just an array of our type item and each one will have an ID a title and a type of access for now let's just simply return the default items so every time now we get a get request for the PF API slash items then we are going to Simply return the default items will which will be an array of our items type okay so now let's go to our main page and we are going to fetch the items from here but before that we are going to create an empty array of the type item let's go ahead and import it and now simply fetch the items from the API SL items endpoint as you can see it's an await of course makes sense so what we have to do is make this whole component a synchronous and now let's just say that if the response went well then we are going to get the Json which will be the items itself and if it does exist and the length is greater than zero let's just save it on our items variable now to check our items visually let's go ahead and wrap this on a div now let's just simply map the items to a new layout so this is only going to be a simple wrapper with the title and a span that will change the color based on the access type of the item and also say which type of access the item has now by going to our client we can see that we failed to parse the URL from the API items endpoint this is because there is no such endpoint API items we have to specifically say where the endpoint is running so in our case the Local Host Port 3,000 but instead of hardcoding the URL on our string what we can do is create a new file which will be called. development and inside we are going to create a variable call it API URL and just give it our currently local endpoint Now by going to the page again let's just extrapolate the variable from the process M and then the name of our variable so now as you can see we have all of our items here displayed on the homepage with their correspondent access type now what you can do is simply copy all of this and simply paste it on all of the other pages so now we can have the items on each of those pages okay perfect so now if we go to all of those pages we can see that we get the list of items from all of them okay so now in order to fetch our data from fir store we could do as I said earlier do it from the client but instead we are going to do from the server and because we know our server is secure because we are good professional then we can say that we could have on the server some administrator privileges which would enable us to fetch all of the data without worrying about the firestore rules so in order to do that what we can do is go to the project settings and under the services accounts we can go ahead and generate a new private key this will give us adjacent file with all of the credentials necessary in order to call all of the Firebase Services as an administrator so go ahead and drop the newly downloaded file on the Firebase folder and now let's just simply rename this to service count. Json now one thing to have in mind about this file is that it contains credentials as an administrator so make sure that this doesn't fall into the wrong hands and in order to have a more secure approach what we can do is go to the get ignore and simply say to ignore the Fire based service account do Jason so this way we don't accidentally push this into our GitHub okay perfect so not that we have our credentials what we need to do is initialize the administrator application in our server so in order to do that let's go ahead and create a new file inside the Firebase folder and call it server okay so before we put anything on this file first what we need to do is actually install so let's go ahead and yarn add the Firebase module and the Firebase admin module okay perfect so the first thing we can do inside this file is to actually import our service account and then let's go ahead and initialize our application by using the initialized app from the Firebase admin and let's passing the credentials with theer also from the Firebase admin module and let's say that this service account is of the type service account okay perfect so now that we have our app initialize what we want to do is initialize the fir store so in order to do that let's go ahead and create a new fir store variable and use the get fire store again from the admin and simply pass in the application now what we want to use in our hold server is the firestore so let's go ahead and Export it okay so now if we go to our items route and let's just try to fetch something from F store so for example a collection name items I know that currently we don't have an items collection but this is just to show you what it's going to happen so let's go ahead and save it and if you go to the terminal you can see that we have a error the default Firebase app already exists this is because that every time a get request is made on This Server it's going to use the fir store and import it from our fir store server the problem is that every time this is imported it's going to try to initialize and application and if it already exists then this will fail because the app already exists so in order to fix this what we can do is actually create a new variable called current apps and use the get apps again from the Firebase admin this will give us the currently initialized apps on our server so now we what we can say is if we don't have any current apps then we are going to create a new one and create a fire store variable from it otherwise if we already have an app initialized then what we can do is get the fire store not from the application we are creating but from the current APP first position because we are going to initialize only one application now in order to export the fire store what we can do is at the top let's just create a variable of the type fire store again from the admin module don't forget it's not from the client module it's from the admin and simply set each to the variable and we're good to go so again in our items gets Endo we see that it is working but it is complaining that it might be or a fir store or an undefined so in order to fix this what we can do is simply say that if there is no fir Store return an internal error okay so now what we can do is from the response of the fire store is get the items and this can be done by accessing the docs variable and just simply mapping each doc to the data inside of the document which will be our items in the end simply return our items variable so if we go back to our client and reload the page we can see that currently we don't have any item what we can do now is go to the emulator on the fire store and start a new collection call it items it has to be with the same name so let's go ahead and add a new field which will be an ID of type string and let's just call it item one for now now let's add a second field which will be the title again of type string and just say that I am a public item so if we are saying this is a public item then we can say that the new field which will be the X will be of type public let's go ahead and save it and now we should have at least one item on our fire store going again on into our application let's go ahead and reload it and as you can see see there's no items this is because currently we are not connected to our emulator we are connected to the cloud we can see that by going into our Fire based project and if we do the same thing we did on the emulator and going back to our client we can see that we now have our item on the fire store but it's not from the emulator and because we are on a development environment we wanted to go to the emulator so in order to do that what we can do is go to our package.json and every time we run the development environment of nextjs we are going to put a new environment variable and we are going to call it next public app m and b of type emulator when you say that the environment variable has the nextore public we are saying nextjs that this environment variable can be accessed not only on the server server but also on the client side now going back into our M development file we can go ahead and create a new variable which will be the emulator fir store PF which again will be the local host on port 8080 we can go ahead and also do the same now for the authentication pth which will be the same Endo except it will be on Port 9099 now what we can do in our server file is say that if we are on the emulator environment then we want to connect to the emulators rather than the cloud version of Firestar and we can do that by changing the current environment variable which is called firestore emulator Host this has to be this variable and change it to our predefined emulator fir store path again since we're here let's go ahead and do the same for the authentication one which will be Firebase of emulator hosts if we now stop the nextjs server and put it up and running again let's see if this is in fact connected to the emulator by going to the emulator fire store and let's change this to something stupid like hello there you go now back in our app reload the page and as you can see now it is getting in fact from the emulator fir store okay so one thing we can do just for testing purposes is to clear all of our fire store data and if we go back into our items get route we can say that if we don't have any items on the fire store then we are going to save our default values but instead of doing an insert on each of the items what we can do is do a batch of updates a batch on Fir store simply means that either all of the updates are saved on the fire store or none of them are so if there's any kind of error all of the transactions are reverted and there is no update on the fire store this is so that we make sure that either everything is saved on the fire store or nothing is so to do that let's go ahead and create a batch from fir store and now for each of our default items we defined on the top we are going to create a new item by calling the collection items. doc this will in fact create a new document for us and simply say that if indeed we have a reference for that item we are going going to set on the batch for that item reference the values of that item finally let's just say that okay now that our batch has all of the information needed to insert in the fire store insert it so we do that using the commit and finally since we are going to return this new items to the user we can go ahead and do that inside the if statement so this way we will have on our fire store at least always these items we created here as a default okay so now that we can fetch the data from the fir store emulator what we are going to do is take care of the sign in again from the emulator and on the client side we are going to create our own provider so in order to do that let's go to our components folder and create a new file call it all provider. TSX okay so the first thing we need is to create a new type for our context and the first thing it will need is the current user which will be of type user from the Firebase off or it will be null this will be the variable responsible for saying that if a user is signed in or signed out next we'll just need a new Boolean to check if the user is an administrator or not and finally if it is a pro user or just a regular user lastly what we'll need is two methods one for the login and again don't forget it's going to be used with Google and another one for the logout now go ahead and create the context for this type with the create context from react and now let's create the actual provider which will receive the children and we'll simply return the off context provider with all of our variables that we are going to Define right now so the first variable for the current user will be simply a state variable using the use state from react and it will be either a user or no like we defined on the type let's do the same for the is pro and is admin variables and set everything to false and for the user just set it to null now let's go ahead and Implement our login Google which for now will simply be a promise with a reject we are going to do the implementation later and don't forget the log out function which will be for now the same as the login Google one okay so finally what we need to do is simply export an use of the that will be used on our context okay perfect so now what we can do is wrap our application inside this newly created Provider by going to the layout and wrap the main tag inside our provider okay so one thing I forgot is that we have to explicitly say that this component will be rendered on the client now if we go into our navbar components we can at the top import the use off from our newly created component and we can already create two functions one to log in from Google and another one to Simply log out the user like so so what we are doing here is simply call each of the correspondent functions we are getting from our provider so what we can now do is render a signing button that simply calls the login Google function we've just defined and be only rendered if there isn't a current user if there is a current user sign in then we want to display the log out button and simply call the log out function not only that but we can also display some information from the user by rendering the display name and the email we get from the current user so in order to implement our login Google and log out function from our provider we are going to need to do the same as we did on the server so we have to create a new application and connected either to the emulators or to the cloud Firebase so we are going to do the same as the server sides but now for the clients so go ahead and create a new file inside the Firebase folder call it client don't forget to import the use client directive so we know for sure that this is run on the client and now let's just do the same as we did on the server so first things first let's get the current apps imported and not from the admin now we are going to import it from the Firebase module because this again is on the client side check if we have currently working apps or not create an authentication variable so we can export it later if we don't have any apps let's go ahead and initialize the apps from the Firebase config which we will get there in a second and finally just put the get off to initialize our authorization variable and the same thing if we already have a current APP let's just finally expl ort the op variable so now in order to get our Firebase config we have to get it from our Firebase project so here on our project what we can do is go again to the project settings and if you scroll down and here you can see that we have a Firebase config variable with all of the variable needed to connect our client to our application so go ahead and create a variable here and we have everything set up now don't worry about these variables the this is not a sensitive data this can be public so there's no need to put this on an environment variable or such because this is public information so it's not sensitive information now again like the server we are currently going to connect to the cloud Firebase and we don't want that we want to connect to our emulator if we are on the emulator environment so in order to do that let's go ahead and do a condition on which if the app environment is on the emulator and we do have the public emulator authentication path then we simply want to connect our authentication to the emulator by calling the connect off emulator from Firebase pass in the current selected authentication and the path for our emulator let's do the same thing if we already have a current APP and now we can already create our login Google function by using the sign in with popup from Firebase and using the Google off provider again from Firebase now let's go ahead and import our off from our Firebase client folder and again because the off can be undefined we simply say that if there is no off let's just reject and return this function for the log out it's exactly the same thing but instead of using the sign in with popup function we are going to use the sign out function inside our off variable now to handle the current state of the user what we can do is do a use effect so this only runs on the beginning of our provider let's go ahead and give it the empty array again let's say that if we don't have the off then let's simply return this we don't want to execute anything but if we do have it let's go ahead and return the on off State change from our off variable this function will basically trigger every time the user is signed in and sign out and pass in the user variable so we can know for sure that if it is null then the user just sign out if it is with values then we know that the user signed in so again if we receive a no value from the user then we know that it's signed off and we can say that the current user will be set to null otherwise if we do have a user that means that the user sign in and we can set the current user to the currently sign in user so now if we click on the sign in with Google button it will redirect us to the Google emulator authentication let's go ahead and add a new account just autogenerate the user information we don't care about that and sign in as you can see we do have the name of the user and the email on the current user States so now if we click log out it will indeed logged out and render again the sign in with Google button so now to hander user roles the first thing we can do is simply clear all of the data so we have a fresh authentication database and now let's go to the functions Firebase and inside the source SCE folder we have a index.ts file this will be the main file for our functions in case you don't know Firebase functions are simply functions that run on the cloud now before we do whatever we want to do with these functions we first need to install everything so go ahead and open a new terminal go to the Firebase functions path and simply type in yarn okay perfect so now what's really cool about Firebase functions is that we have some special functions that trigger every time a state changes on authentication fire store storage or whatever and for our use case we are going to use the off user on create so this is triggered every time a new user is created in our application go ahead and import it from Firebase functions and again before we do whatever we want to do with this we have to initialize and connect these functions to our application and we can do so by calling the initialize app and pass in the configuration now what we want to do every time a new user is created is to actually create a new users collection on firestore and set that new user to is pro false so we can do that by doing so so let's import the fire sore from the Firebase administrator because again these functions can have administrated Privileges and let's choose the document for the users collection and with the user uid we get from the newly created user and I'll simply create a new object with the is pro equal to false so every time now a new user signs in in is created in our application we know we will get a regular user on our fire store okay so now just for testing purposes let's say we do have an email we know for sure that it's ours and it is someone that has a pro account so what we can do is get the email from the newly created user user and if that email is equal to Pro example.com for this example then we can create a new user in our users collection with the is pro to true and then simply return it now let's say we want to do the same thing but for an Administration email let's say that okay sure if you are an administrator then you are a pro user also so we set the is pro to two when creating the user on the fire store but now instead of having a aable on our fire store to check if the user is an administrator or not what we can do is use the custom claims so go ahead and create a new object call it custom claims and give it a role of administrator and now what we can do is actually on a tri catch block use the get off from our authentication administrator module and call the set custom user claims function this will set a user claim on our authentication provider not on the firestore provider so in this way we can get the claims from the user itself and not from firestore and then simply return it okay perfect so now to actually put the changes on the functions what we have to do is build it with yarn build and now simply stop the emulator and run it again to get the changes from the functions okay so before we test this we are actually going back into to our components and to our off provider and what we are going to do is say that if the user sign out then again not only the current user is equal to null but also the admin in Pro is equal to false now if the user signs in what we can already do is check if it is an administrator or not to do so we are going to take the token values from the user Itself by calling the get ID token result function and then we simply set the admin if the token values do claims. roll is equal to the admin we defined earlier to check if the user is Pro or not what we can do is fetch the user data from our API which is not currently implemented we will do so in a bit and then simply say that if we did in fact have the response then get the Json and if that Json has the is pro that is currently set on the F store then set it the pro to True otherwise let's just log an error say that we cannot get the user information okay so let's go ahead and create a new API route by creating a new folder call it users and we want to define the endpoint with the custom ID parameter so what we can do is create a new folder and in Brackets we say user ID and inside this folder we are going to create the route. TS this way we can extrapolate the user ID from the PF bypass in in the params from the get function of nextjs surround everything with the tri catch block like the previous endpoint let's say that if there is no fir store let's return an internal error and now let's get the user from the fir store collection users we can do so by calling the fir store do collection which will be the users Collections and the document which will be the user ID that we get from the PF on the endpoint finally just doget to get get the document get the data by calling the dot data from the document itself and then simply return the user data whoops okay so this is inside the TR catch sorry okay so lastly just to check which type of user we are dealing with we can go to the components and inside the KN bar let's just render a simple tag saying user if the user in fact is logged in but it is not uh neither a pro or an admin administrator do the same for the pro user and finally for the admin user each one will have a different color so we just have a visual cue on which type of user we are talking about so now by going to our application let's sign in with first a random user so go ahead and autogenerate the user information and we can see that it is in fact a regular user let's log out now let's sign in with the pro example and let's say Pro user sign in and as you can see we have the pro tag for the pro user again log out sign in and finally let's create the admin account let's just say the name is I am admin sign in and as you can see we do have a problem here so the time it takes for Firebase to actually update the claims is a little bit delayed from the time it gets the user information so in order to fix this we can simply log out and sign in again with the administrator and as you can see we already have the updated value and we are in fact on an administrator account okay so now that we have some user roles we can start by creating some Dynamic page routing so in xjs we could in fact do the page routing on the client side much like other Frameworks like react or angular but instead we are going to use SSR but in order to do that the server needs to know who is calling the page and the way to do that is by using Json web tokens stored in the cookies if you need a refresher on Json web tokens you can click on the card on top of this video to make our jobs easier when handling the cookies what we can do is install another module called GS cookie this module doesn't come out of the box with the typescript type so what you can do is actually yarn add minus D for the development side the types of the JS cookie now going back into our off provider at the top we are going to create three functions so the first one it's the get off token which will return a string or undefined and we will use the JS cookie Library so import cookies from JS cookie and it simply gets the Firebase ID token cookie so we Define this value and what it does is if there is in fact a cookie with that name it will return so otherwise it will just return undefined now let's do the same for the set token and this time we will pass the token string we want to save on the cookies and we also pass in the secure options lastly to delete the cookie simply create a remove of token function which will be the cookies. remove and then the name of the cookie we want to remove okay perfect so now if we scroll down and every time the user signs out what we can do is already remove the token if there is one and lastly if the user signs in we can indeed create a new token by calling the get ID token from Firebase and this will generate a new token every time this user signs in and we can simply set this new token and save it on our cookies so what we can now do is go to the user page in at the top simply calling the cookies function from the next headers module now with the cookie store we can get our authentication token by getting the same name we defined earlier for the token and getting the value what we can now do is say that if there is no off token meaning that either the user is not signed in or it doesn't have the token then we can simply return an header saying restricted page so if we log out and refresh on the user page you can see that we get a header with the restricted page and we don't get access to all of the contents of this page or if you prefer you can actually redirect the user to another navigation path so let's go ahead and comment this and now if you refresh the page go to the user page you can see that every time we click on the user page we get redirected to the homepage if we sign in with a random user go to the user page and you can see that we now have access to the user page and all of its content so now what we can do is say that every page needs at least a user to be signed in except the homepage so go ahead and copy all of this and on the pro page just paste it on the top and do the same to the admin page okay perfect so now we know for sure that only if you are a sign in user you can access all of those three pages except the homepage which is public now in order to handle authentication on the server side we will need to import the off object that we created from the client but this time on on the server so let's go back into our server file on the Firebase folder and inside let's create a new variable call it off and it will be off the type off from the admin module now simply do the same as we do with the fire store so off get off and also if we have a current APP running finally just export the off okay so now going into our Pro page we know that if the user is not sign ined it will return a restricted page header now we just need to know if the user is a pro member or not to do that the first thing we can do is actually create a user variable which will be off the type decoded ID token from the Firebase admin module and we are going to call the verify ID token from the token itself so in an NHL what this does is to extract all of the information of the user from the token that's receiving we can also add here the condition that if we don't have the off then simply return the restricted page and imported from our Firebase server so now that we have our user information we don't have the full information that's stored on Fir store so we have to fetch it from fir store and we can do so by using our API we just created and passing the user ID that we've just decoded from the token to make sure we can say that if we don't have a user despite having an authentication token we can simply again return a restrict H page header now from our API we will get all of the user information and we can say that the user is in fact a pro member if the user information has the is Pro Set to true if by any chance there is no user information or there is but the user is not pro then we do again the same and return uh header saying restricted page so going back into our application if we now try to access the pro page with the regular user you can see that we get the restricted page from the server if you try to log out and again reload the page we still get the restricted page but if we now sign in with a pro user and refresh the page you can see that we get all of the information from the pro page lastly for the admin page it's way easier than the pro page because we don't need to fetch the user information from F store so so go ahead and copy all of this and on the admin page simply pasted here at the top now let's import the off from our server and we can check if it is an admin or Not by accessing the RO attribute on the user object if it isn't simply return again a restricted page header back in our application if we try to access the admin page with a pro user you can see that again we get the restricted page so let's test it out with another admin and there you go we have the full information for the administrator and as an administrator not only you have access to the admin page but you also have access to the pro page page the user page and the homepage so now fetching the data based on the user role we will have a small problem in the page component we can get the token from the cookies because it was the client that called this endpoint so every time the user tries to access a new page an endpoint call is made to the page components and therefore we do have access to the cookies but unfortunately once we get for example the items over here this is not the client that's making the request to our server it's our own server on the PES component that's trying to access again our own server on the API endpoint so we have to somehow give it to him explicitly the tokens of the user and we can do that by passing in on every fetch we do to our API a new header with the authorization and then just simply do a string with the be space and then the token that the user G to the page don't forget to do the same thing on every other fetch for all of the pages including the homepage so once you make all the changes for all of the pages by sending the token on the header what we need to do now is go to our items route and at the top we can get the token from the headers on the requests and get the authorization and just simply split the beer and get the latest value either that or we just passing n so now that we have the token let's go ahead and decode the user and let's say that we only want to decode the user if we do have in fact the off object and we have a token because if we don't have a token then we don't have a user and this is rendered obsolete let's check if the user is an admin or Not by checking the role to check if the user is a pro member or not we have to get the user from the fir store and we can already pass in the token for the users API call because later we are going to protect it from other users using it so again let's check if the user is Pro or Not by getting the E Pro from the user info and now instead of getting all of the items from our fir star collection what we can do is create a new variable called at fir store call for example and let's just say that if we do have a user but the user is not pro and it is not admin then we want our call to be the following so we get the collection items again but now we say that we only want where the access attribute is inside of one of these variables the public and the user meaning that this call will only fetch all of the items which have on the access either public or user otherwise if we do have a pro user then we get again the collection of the items on which the access is either public user or Pro finally if the user is in fact an administrator then simply get all of the items since the administrator has access to all of the items otherwise it's not a signin user so we are just going to return the items which the access is equal to public now just change the response here to get the fir store call and if we go back to our page we can see that there is no signning user therefore we can only see the public items if you go to a user page we get to the restricted page so if we sign in now with a let's say a pro user for example then we also have access to the user page but we do also have access to all of the pro user and public items by going to the homepage we get the same thing so independently on what page the pro user is it will always receive all of its Pro user and public items to fetch all of the items one will have to sign in as an administrator so reload the page and as you can see we receive the last item on our fir store which is of access admin now one problem with our users route approach is that anyone can call this and I don't know about you but I don't think that's very safe so for example if I'm a pro user or whatever user I am I shouldn't have access to the user information of another user so in order to protect this let's go ahead and simply copy and paste what we already created this way we not only get get the user but we can also check if the user is an administrator or not and what we're going to do is create a variable that checks if the user is either an administrator or if the user ID is equal to the endpoint ID meaning that if we are an administrator then we have access to the information of all users and if we are not then only the user of the endpoint can get the information so let's go ahead and if it is not valid then simply return an unauthorized response don't forget that for this to work we have to now send the header every time you do a call onto our users endpoint so we have to send the header on the pro page and we also need to send it on the off provider since we are making right here a call to the users's endpoint but because we don't have the off token we can actually get the token from the user. get ID token function okay perfect so now you know how to do authentication and alization in the next year project using Firebase not only that but you also know how to create your own emulators and handle the authentication not only on the client side but also on the server side by using the pages and the API route you know now how to create user roles and render dynamically the pages according to each of the user roles and not only that but also how to dynamically get the data from the fire Star based again on the user rle I hope that this helped you and I'll see you guys in the next one cheers
Info
Channel: Miguel Vieira
Views: 645
Rating: undefined out of 5
Keywords: authentication, authorization, firebase, nextjs, next.js, user roles, server side rendering, firebase admin, page routing, user based data fetching
Id: -BEqV6eaaQk
Channel Id: undefined
Length: 52min 0sec (3120 seconds)
Published: Fri Oct 27 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.