Transcript for:
Angular Vietnam Presentation Overview

[Music] [Music] hey hey welcome everyone can you hear me now hello can you hear me now so i'll start again i think uh the the my the marvelous milk the my the mic smelled it so i'm gonna start again so welcome everyone um this is the first angle of vietnam in english and this is the first time i'm streaming in english by myself so i'm going to speak english for a little bit and i'm going to speak vietnamese i might jump back and forth so excuse me for that i'm going to introduce a little bit in vietnam i'm going to start again i'm going to introduce a little bit in vietnam uh in vietnamese so so people understand the rules because this is the first time again [Music] um i was just explaining to to the vietnamese audience that um if they have any words that they don't understand or i speak too fast feel free to stop me so today on the agenda we have authentication we have authorization and i'm going to talk a little bit about tnc scholarly um um if ever if anyone doesn't know tnc scoli is a repo of my personal blog that was written in um scully which is the static site generation generator for angular and then we're going to talk about miscellaneous stuff i'll answer common questions whatever you guys have and if nobody nobody has anything i'm just going to stop streaming and early all right and now this is angular vietnam so authentication authorization is on is all in angular how i do it how experience is it doesn't mean that it is the best practice so feel free to stop me ask questions or we can discuss okay so let's start off with uh authentication so a lot of people know um authentication um is it always deals with local storage or token i'm talking specifically about jwt or json web token based authentication and a four four uh to explain it a little bit more uh authentication is to verify um i guess to verify who they are or right to to verify who they are then authorization is to verify what they can do so authentication is um um is login stuff and then authorization is permission stuff so it's two different things you might be authenticated you but you might not be authorized that's the two main concept so first about jwt uh i've read a lot of blogs and a lot of strategies about how to handle um token on the front end like a lot of questions pop up like oh should i should they store the um the token in the local storage or should i start a token in uh cookies uh what's more secure um what should it save uh what data should it save on the token it's hard like security is hard i'm not i'm no expert in security anyway so um then i stumbled upon this guy this is the ultimate guy to handle jwts on front end don't care about the craftql part you can apply this to rest api as well and this is the best blog ever that you're going to read on jwt so i'm going to i'm going to link the the url in the chat so basically in this um in this guy they would talk about um the strategy of having a an access token and a refresh token the access token let me scroll down a little bit uh refresh token there we go so the the access token is the token that you usually use that's your that's your familiar token to to give to a client to have access to your data that's the access token that's the if you if you're familiar with the backend you will have the authenticate method to to verify the token from the authorization header like the authorization bearer header so i could verify that grab the information from that token and then grab the user from the database in the database based on the information on that token so that's the access token so what about refresh token so refresh token is is a token to refresh the access token so because the access token has access to your data it needs to be secured and it cannot be leaked so the access token has a very short lift it it can be like anywhere from five minutes to 15 minutes to an hour it depends on depends on the requirement it depends on your applications and then the refresh token might leave like a week a whole day it depends again it depends the duration of these tokens depends i'm going to talk about uh the concept first i'm going to show the code is the same thing with authorization so for the access token and then now people ask where do we save these tokens so the access tokens we do we do not save the access token we save the refresh token and or we save the refresh token in cookie so it's a little bit hard to to to to to to visualize so this is a quick visual demo so when a user login when you use a login what we do is we we return the refresh token so we return the refresh token and we we as the header as cookie header so that the browser will save this refresh token in the header in the cookie we also return a an access token and an access token expired so when you when you log in you will have these two tokens and the expiry of the of the access token then we store the access token in memory only what what do i mean by in memory in memory mean that you assign it to a variable called access token equals integrity token that's basically it and this access token leave in memory so when you refresh it's gone when you refresh the page it's gone that's when the refresh token comes into play so again because you save the jwt token in memory so it's not it cannot be leaked like like the people can read your code but people cannot read what you store in the code right so now you have the access token you're going to make the request with the access token i'm going to go to that in code in a little bit how i implement it and then so when you refresh the refresh token in cookie will actually go and refresh like call a refresh endpoint to refresh to get the new access token and again excited access token on on memory so that's the whole flow of refreshing token and then the access token so you have a pairs of tokens and i believe that is the most secure way to to to do these things with the token based authentication now let's look into code let me bump the size up a little bit we have college schemes from 18. um this is um a project that i used to work at my previous at my previous job now because it is my previous job so i don't have access to the database anymore so i cannot demo it i can only show the code and i walk you guys through the code how i do it uh so for this stream we're gonna look specifically in the off uh folder here under common uh the permission folder and also the security folder now let's look into the security folder um actually let's look into the app routes first so this is router uh routing configuration so for for routing configuration you can see i have at my top level i have three config one is for a redirect to dashboard uh one is for the authenticated guard i mean uh off layout component so this is the layout component when people have been authenticated after they log in and then i have a public layout component so public layout component is for when people are not logged in so to show them the register page or to show them the login page so that's the public layout and you can see these these configuration the path so again i'm gonna put i'm gonna put this up because i feel like this is important since i'm doing this for the first time good calling me like so to to my english um viewers uh i'm saying as soon as you open the code then i know and then i understand what you're saying it means that when i speak english he might not be able to understand please guys i don't i don't want you to feel feel that way uh let me know stop me uh so i can explain it in in vietnamese if you want all right all right so go back to to the off route so you can see right here these guys have the same path but this guy is put before this guy so when the angular router looks into the route to resolve the url it will actually go in here first and if this pass the guard then it will go into the off layout component and it will skip the public layout component if the guard is not passed which means the the person is trying is trying to go to the dashboard is not authenticated then the public layout component gets rendered and then at the first path it will render my security module so that's the flow so when the user when the user hit my demand and with the router actually check authenticated guard check authenticated score if passed then go to a half layout and then off layout actually have a redirect to dashboard so it will go to the dashboard module and then it has passed the permission guard as well right if it not passed if it's not passed a past then we'll go to public layout so that's the first uh that's the first flow and we're gonna look into the authenticated guard and we're gonna look into the security module let's look into the security module first it's very simple uh the security module is just um right now this um actually this one is a rewrite um i was rewriting um of the past over the last couple of weeks uh so it doesn't have any register or it doesn't have anything else rather than a login component yep so if you look into the login component it's very simple you have a login screen and then uh that you have an auth service hit login excuse me you hit login and that's pretty much it that's pretty much it and then if you log in successfully i will navigate you to the dashboard let's look into login so on login i actually have um i actually called the request token and then after that i will call the after request token so at this point let's let's assume at this point the user is trying to log in and then they input the email and password uh email and password and i'm gonna call the request token so security client is let's go all right so security client is a um a class that was generated uh we're using we're using swagger so it's generated all of these bars and all on this security client it will have a request token and this request token actually hit the endpoint called security slash token so this one is our login endpoint so this is the login endpoint and then after so so so the security client will call the request token and then i have a custom type called after request token we're going to look into after request token what it does so after request token we'll look into that later if there's any errors from the server then i'm gonna switch by the arrow key so maybe invalid credentials so username password incorrect user account has been deactivated or password has expired so if any of these cases then i return the error to this observable so that i can display the error on the login screen so at this point the user is not authenticated yet and then assume they are authenticated and then i call the after request token and in here in after request token the first thing i'm going to do is i grab the refresh token from the request from the response i got back from the login endpoint i got the refresh token and then i saved that in local storage um i was i was pointing out that ideally you want to save the refresh token in cookies but because this app was not built cookie based because we have like a mobile application as well so on the front end for this one we're using local storage again not ideal is is vulnerable however refresh token doesn't have anything it doesn't have anything um greenwing um so okay now you can activate the cantaloupe like you can uh so you can ask what the difference between can activate and can load i'm gonna i'm gonna explain just right now real quick if you go back to this you have a can load and can activate so can activate if this passed it will activate the auth layout component for this guys you know that we have lazy load so can load uh for permission guard right here if can low pass it will actually load uh this bundle if it doesn't pass it will not load uh if you put can activate here it works the same way but it will still load the bundle it will it's just not it just does not navigate due to that route but it will still load the bundle and that's a waste you might not want to do that you want to say can load on um on any route config you say load children so that you don't load uh the the bundle because you want to laser load it if you lazy loaded it and then you don't allow people to go to it it's a waste all right okay back to my off service so i was explaining how uh how i had to use local storage for this application and because the refresh token we don't have any information really uh to that that very um i guess compromised security compromised or vulnerable basically that that then i i just saved in local storage uh for the sake of of this app that's how the back end was written and then after that i would set up a refresh timer so when um with the refresh token you want to refresh when the app refresh basically when the when the user hit the refresh button or when they go to the the application basically when they go to your url on the other hand you still want to have a refresh timer because the access token only has like 5 minutes or 15 minutes to leave after 15 minutes if you don't uh refresh the token silently if you look at the or the article they will say something about silent selling refresh uh they will talk about silent refresh so if you don't do silent refresh basically after every 15 minutes you're gonna force your users to log in again so at this point i'm gonna set up the refresh token and again as a reminder the app after request token is after the the user has called the login api and their credentials are good so let's look at the setup refresh timer so for the setup refresh timer i will have the expired of the access token again it is 15 minutes then i will minus from that 15 minutes into 14 minutes so basically 14 minutes at 14 minutes so so at one minute before the access token is expired then i want to refresh basically that so basically if they use the app for like 14 minutes oh the app my app will say oops it's 14 minutes it's gonna expire soon let's refresh so that's what i'm doing right here so i say the diff in milli so the difference in milliseconds um is this is like 14 minutes from now that's the from now 15 minutes uh 14 minutes from now and then i say a timer so timer this timer after 14 minutes will emit and if it emits i do what if it will emit i will call the refresh token so basically this is after um one minute actually after 14 minutes so this is one minute before the access token expires refresh refresh the access token if if the user keep using the app over and over and over it's just like every time i refresh 14 minutes after that i will refresh that token again so let's look into the refresh token method so refresh token is hey i grabbed the refresh token from the local storage so my art talk is the refresh token key if i don't have any uh refresh token in my logo storage i just reset my my authentication state and i redirect the user back to login so basically they if they don't have any token and refresh token in their local storage then i would just redirect them back to login and stop doing whatever whatever they're doing next if if they have a token then i will i will try to refresh it so this again security client uh refresh is a method that we call the refresh endpoint and pass in the token uh which is the refresh token by the way and then if i have an error if if everything's good if everything's good let's not look at this line if everything good then i will go back the whole after request token again to go to go back the uh to go through this flow again i'm gonna go back to this one again but basically if everything is good then i go back again i save the new the new token in the local storage and then i set up a new refresh timer if everything is good if something goes wrong and if that errors is a 401 which is an authentic or unauthenticated which means this token is wrong something wrong with that refresh token that refresh token is expired so imagine uh somebody log into your app and then just leave it there close the browser or whatever and then they like a week later only seven days later they go back to your app it depends on the the duration of your refresh token it might it might be expired by the time they log back in so student gaming um local storage services that's talking about logo story time um so student gaming as local storage service dot set is to save the token to local storage yes it is i just i just wrap local storage around a service so i have so i don't have to do like json.parse or json.stringify because you know local storage only only works with string so just have a local storage service to wrap around local storage so at this point i have a 401 which is unauthenticated again the token might be expired the token might be tampered with a tempo with means somebody trying to modify the token maybe they're a user but they're trying to modify the user uh the token into an admin so that's that means it tamper with if it's for one mean do something if the fresh token is unauthorized am i i might show like a message something like that here but if it is if i got a full one from the refresh token i redirect them back to the login so the flow right now is right they log in they log in set up a refresh timer right that's that's done when the refresh camera emits refresh the token refresh the token so that's the current flow right now and then after refresh token a new timer a new timer gets created so this this is this this is the cycle right here actually writing this is a cycle but after they let's say if refresh token if refresh token failed fail with four one it fell with four one then just redirect to login so basically pick the user out ask them to log in again so they have a fresh access token and a fresh refresh token again if if it's a uh not for one then i just say i just reset the state and i throw an error at this point i don't know what happened i really don't know what happened unless the server tells me more tells me more about the error what's wrong with this token so i can do more here so i can like do more with more information at this point i don't know i just throw the error and then the app might just hang or whatever [Music] so all right so that's the refresh token which is from the setup refresh timer which is from writing so um this is after they actually log in successfully so next one next one you have a switch map so why do i need to switch map right here it depends on the application so at this point is what you have is the access token already so at this point you might be able to start fetching for some user information so right here i fed for like some information about this account the user account so if they have like transactions or something like that you don't have to have this like this block you don't you just need to have excuse me you just need to do to have the setup refresh timer and then do whatever you want with it i have off an auth state service so we're going to look into that later so the off service is to handle all these api calls and all this set of refresh timer but i you can see that i do not expose any like token or any current user from my off service and that is in my off state service um so random could you discuss about token in the server side how to generate uh what the difference between jrt and oauth2 again so to answer that um yes and no so what yes means yes i can just discuss about the token in the server side but not for this application because this application was a part of my previous job i quit the press job now so i don't have access to to the to the latest code or to run the application or to show you the database any of that i cannot do that for this particular application but i can talk about the token on the server side uh in a different app in the backend that i wrote in nash jazz this one the backend for this application which bring in net core but i'm not very good with uh.net core so again i cannot i cannot discuss that in this string in the stream also the difference between jwt and oauth 2 is two different strategies to do authentication i do not again i'm not a security expert so i cannot tell you what the difference is up top of my head that needs some more research and some more asking around so thanks for asking but uh yes and no i'll do that in the next video in the next stream on the token on the server side because i do not repair the repo here so i cannot show quickly uh okay back to off stage service so my off-state service is what i use to to to store all the data or the refresh token all the uh actually not no refresh student the access token and the current user information and stuff like that in my off state service right oh and again because again i worked i should i should have used a different application but whatever the token request so the um uh the the request the login endpoint for this application returns also the user returns the user information as well this user information it doesn't have anything really it doesn't have so it just happened user information it does have some some information about this user but no confidential or no security related to information it does have some roles and rose id and stuff like that i'm going to talk about growth and permission in the in the authorization part but again is it's a little bit different than what it would do what it would do is i would have a different endpoint called like slash me and then i would call that that endpoint when i have the access token to grab the user information i do not return the user information uh for the login endpoint at this point i have the user and i just save everything to my off stage server so i you just imagine just imagine that my off stage service has all all of the information that i need to do whatever i want to do so now this is the whole authentication flow um in the auth service so when they refresh when they log in what happened this is what happened all right so next we're going to look into the off-stage service so off state service i expose the token expo the token expiry uh the current user is they authorize or not and stuff like that to to to drive the ui based on the authentication state of the user if they log in or not so yeah it's very simple just like these so i do so i can do stuff with it basically the token and the token expiry we're going to use these two in the interceptor so we're going to look into the interceptor next which is my off there we go so as you guys know um angular http client they have http interceptor so basically this is to intercept the request going out to append anything you want to the to the request and what we want to do here is to append the better token uh the better token the authorization header to the request so that the backend can verify our request um i just forgot that this app almost learned from an end through angle okay uh what what gonna ask why we have to save refresh token i think we should we just should save access token in client yes you're right we sh we do not save refresh token again as i said for this application because the backend is built not on cookie based so i have to say the refresh token in local storage if i don't say the refresh token in local storage i don't have anything for the user when they refresh the page i don't have anything from them to actually go grab the new access token from them for them so ideally you have you save the refresh token in cookies and that is going to be if the if the back end is built uh based on cookie then when you log in the backend will return a headers with a cookie uh of the refresh token then the browser will save that refresh token you don't have to do anything with that refresh token right so for this particular app i i saved the refresh token because i need to [Music] ask why do i use switch map and fork joint uh here when i have the token request from the login endpoint because so i switch map because i have to call something i have to call some api and that's that api call isn't observable so i have to switch map and again the whole thing the after request token is a function that's returned let's return me a new pipe a new operator basically so that you can see right here that i type this lock request after request token so if i even just grab everything in here if i just grab everything in here and it dropped into this then you will see that i have to use switch map because i'm going up off a stream so i have to switch map to another stream and then i use fork join because i want to i want to have the token request as well however you don't have to use full join here you can just do this and then you can pipe a map to this one and this one is the check account transaction and then you can just return both both of them so this is one of the token requests and checking out check account transaction right here so you can get rid of the fork joint i hope i don't have that cooking requests um let's return that and here oh because um i have to return this other castle i'm gonna check the account content section uh let me pass this one in then i'm gonna hide a map i have my check account and then i'm going to return a token request and then i check it out why does this yell anyway you can do this but you have to fix the typing you can do this this is this is the same as this one all right so that's the that's the reason why i have to use switch map and fork join yeah i have saw you use okay it's okay uh time to uh answer questions so uh once i asked i have saw you using timer to refresh token sometime other developer will only refresh token when client get four one what do you think about two solutions and pros and cons about them great questions uh to be honest with you uh i do not depend on when the user get the full one because at that point you're gonna have to uh you're gonna have to i guess handle the current request in the pipeline so basically when they let's say they they send five requests and the second request get full one now you have to to like basically stop the three requests that's still in the pipeline and then send a refresh token and then goes back to the fourth um the the three including the one that just failed so i have that in the interceptor which i go through as well but then if i have a refresh token a refresh token set up then i don't have to worry about a user getting 401 that much because i already already refreshed them that's the pro the con is you might refresh too much let's say the user might not need to refresh that much but again i said i set a timer at one minute before it expires so it is a long time too so that's that's the pros and cons of the refresh token at the timer uh yep um because prevention is better than current then that's that's a good way to put it too but yes there's a pros and cons set up a timer you have to you have to to to decide when to refresh you have to set up the code to refresh and then you have to like set up to write the code to cancel the refresh timer if there's new refresh uh if there's new token coming in it is a lot of stuff to think about but it just makes your interceptor a little bit easier uh next one is miss windows where is the best place to store token and refresh token cookies local storage in somewhere so miss windows at the beginning of the stream i share an article um i share an article that is says refresh this is this one um this is the best article that i've read on um storing token in cookies on local storage or somewhere but too long did read is for for this for this article we have two tokens refresh token and access token with the refresh token we will save them in cookies with the access token we say them in memory which means it's just a variable when you refresh that variable is gone that's the access token but uh what happens when you refresh so when you refresh you're gonna grab the refresh token that you save and we're gonna go to the back end and ask for the new access token and then that new access token will get assigned to a variable and then your app will work again that's the whole deal of refresh token and access token right back to uh back to the uh interceptor so now i have the let's let's let's assume that i have the access uh access token saved in my memory in all state service uh here in in the art interceptor i have an add token so editor going to just set the headers on the request to have the better token uh next one is a function called refresh to count request so this is what manager said so if i have let let's just go over when i call this function then i will go back to this function and then i have the new token to call request right here so uh that a new token to call request basically just have the token in the off state service and then a merge map it over to uh to the um to the new request with the token added to the headers so at this point i have the new request and then i just return that new request with the header so that's the new token to clone request right this is the intercept let's start let's let's start from from from top to beginning intercept first of all if this interceptor gets invoked i just say hey i have some allow url allowed url means uh this list right here this is the list of endpoints that i don't want to do anything to it so basically if i have a refresh request the refresh request going out i don't need the access token because this is actually going to grab my access token for me so i don't really want to try to append the access token to the refresh endpoint also for the assets sometimes um the angular or the angular sign will actually make requests to the access um your access folder and it will actually go through your interceptor so i prevent that as well so if if i have uh if the euro of the request coming in right here request.url has those endpoints then i just say hey don't do anything just go i don't care about your your request if you invite if you're in the allowed list and this one i have a flyer called has retried so here you can have a number of retries or you can just say i will try once so this is i retry once if it still fails after i retry i go to go back to login i don't care anymore so that's the history triforce so here you can have a number like we retry cow you can have like a green retry cow maybe like five times or something like that it's up to you so the first thing is i can buy latest uh the tokens and the token expiry so over here is me trying to grab the the current token and the current token expiry l and token this token is the access token again and then i take one so i just need the the latest i don't care about the next one i just need the latest at this point then i have the token and then i have the expiry if there's no token no token i say no token just go you don't have token go i don't care then i i i will handle the request the fair request because at this point if there's no token and then and then the request goes out then the request might come back as a 401 because it's not authenticated then i will handle it somewhere else at this point if they if you don't have the token just go i don't care all right so the next one is here a cloned request this one is say hey i want to add the token because i have the token now i want to add a token to uh to my request so now i have the clone request with the token next i have defer so defer is a mechanism you want to use when you have a retry win so i'm going to explain defer when i go through what inside of the differ right now the first thing i'm i do in the referrer is i check if the token has already expired if it is expired i will refresh the token first right i will refresh the token first and then i will go back to the current request so let's look into the refresh to call request so refresh to clone request is concat the refresh token and then i have a new token to clone requests so this this request right here is the current request going out so that's my current request going out the refresh token is the refresh token endpoint or api call compat means hey go do this do this first and by by do this it will go here and it will go through refresh token and go through all the setup refresh timer all the stuff that we do in off service then because it does all the stuff that we do in our service and after request token i will have my new access token saved in our state right so at this point i have all the new stuff again if everything success all the new stuff new refresh token new access token and then they say hey now use the use the new token and add the new token to the request header of the current request going out so let's imagine let's imagine you call a product and this one the token is expired then i will refresh the token for you with this after that i will grab the new token it's this and then i will recall the product with the new token so that's what these two function does so that's this is the whole flow all right so that's when the uh the access token expired right here if it expired if it's not expired so if it if it gets here if the code can get to live 80 it means the token is good and the token has not been expired then i would just say all right go ahead call the request make the request and then the request my success or my phone if it fail then it will have an error then you can use retry when we try when we will take in the error observable and you can do something with that error observable so basically if now let's say my request goes out and it failed it might fail because of something i don't i don't know then i say hey you fail okay i know at this point my token and my expire is good i don't know why you fail but okay you fail so at this point you fail right i will check if the error is 401 again if okay we might send a bad token so we can make a full one from the server if it is 401 and i have not retried so at this point i have not retry yet okay all right i've set the retry to two so i retry once only once and then i called the refresh clone requ two requests again so basically i try to refresh and then resend the token again with the new token because because clearly the server say by something wrong with my token so i just okay i'm gonna retry once for you and then if after that you still fail i'm done i just return you an error i don't care at this point i'm done at this point i mean at this point i'm done i don't i don't refresh anymore so i reflect what i refresh once so that's the whole retry win and when you read uh whenever we try call retry when we try when we'll actually go back to the defer and we'll go back to here so it just basically is is my way to to do retry when because i want when the code when this code in here retry new value new value because you know things might get passed by by reference in javascript so i just do defer to make sure that these are new value in here right so that's the whole uh refresh thing then we have more we have more catch error down here so again after i refresh but you still get 4-1 you still get 4-1 okay okay dude i'm gonna lock you out i don't care anymore i lock you out and then i redirect you to login so at this point at this point the user we have tried everything that we could we tried to refresh the the token for them we tried to resend the request for them but they still fail that means that their account might have been deactivated like right they might quit their job but it's still trying to to access the application so at this point something happened to their account that we need more investigation but as far as the front end cares lock them out and redirect them to login so at this point right if they are not authorized which means they try to access a page that they do not have permission to redirect them to not authorized so that's the whole flow if if it's not if it's none of these then just throw the error and then i'm gonna handle the error on the front end so maybe th show like a notification uh something went wrong or something like that so that's the whole interceptor so it again to recap in the sector grab the new token i mean grab the access token and the token expire to handle refresh also to handle retry and to handle adding a token to the authorized authorization header so that's the two main part of the interceptor uh next one is we have the guard uh the guard where is the girl right here so we have the authenticated guard it's very simple to say hey it's authorized and uh it's authorized it's just if they have token or not so that's the uh that's the authenticated guard so if just to remind you go back here authenticated girl and so at this point when they refresh i'm gonna i'm gonna check hey do do you have um or do you have token or not if they if they do then they authenticate it then they go in here so that's the whole authentication flow so not just the part of login token and stuff like that there's nothing related to permission yet all right so uh we're gonna take about two minute break two three minutes break uh see if i have any questions um what do you guys think any question any any part that you want me to explain again uh wait my name um magnum wing asks really curious why you're typing so fastly wow i tie fast but i type wrong all the time so there you go so it looks like there's no more question i'm gonna drink some water then we're going to go back to permission uh so permission is another whole beast and permission authorization is actually very um actually depends on the backend uh implementation a lot so i'm just gonna show what we have here do not take this for uh for good practice or for general practice because it's not it really depends on the back end but there's also an article about permission so it's beeswax i'm going to share this in the chat our backend based on this because we actually have account we have user we have row and then we want to add permission to it excuse me to go to quickly go go over this so for permission we have create um read update and delete so basically the current um the square so basically that so we're gonna we're going to assign the read to the value one to create to value two the update to value for the delete to value eight so why why do you think that there's one two four eight here these are binary these are binary so if you look into uh if you if you know binary number you know one is one you know two is ten you know four is one hundred and you know eight is one thousand so if you if you and to write in a little bit more accurate so it's this way so zero zero and then zero right and then because it's binary so it's one zero so it's just on or off or true or false so because when we use binary for this permission is we it's easy to to combine those so let's say what what if i have a user that can create and can delete but they cannot update it's weird but it might happen right so i need zero zero one zero and one zero zero zero so imagine if you do this with like uh uh can uh can read can't create can update can delete can read and create can read and update can read and delete so four so for four uh operation create read update delete you will have 15 flags for for all of the uh combination so with uh so with the binary you can do a very quick things like this so let's say i want to have a read or update i want to read or update so it's going to be one um or update hold in and oh yeah um zero one zero zero sixty five that doesn't look right i'm gonna show you the code because i forgot to it's been a while so i'm going to show you the code but um it's going to make sense later it's going to make sense when i show you the code for why we use this all right uh you mean a dashboard some refresh page you can pass the permission storage api delay permission so you you can ask if we in if we on the dashboard and then we refresh the page does the user yet pass the permission guard in the case we don't save that information the user information in local storage and we fetch the user on refresh yes yes we can we can why we can because the guard the god itself can return observable so in the guard you can actually set up uh set up your guard to return an observable to wait on some sun operations yes you can do that which we're going to go through the we're going to go over the permission bar to to to see close closer all right men asked what happened if we have async test an app component and a guard in the route all of them will run async right yes all of them will run async yes all of them will run async but but you can set up your async task in a way that it it happened in a stream so maybe some flag before that for for them to run which again i can show them i can show you later too all right so let's just go let's just go over one question uh because i can show the app component real quick so app component as men said all right ad component will run because it's not it is the is the top level component so in my energy on internet i just set up translation you don't have to worry about this setup router title listen i don't have to worry about this right and then what happened what happened is when when the user refreshed or on my in my engine on init of my app component i say retrieve token on page load so what this what this does it actually call the refresh token and that's it right it will call the refresh token the refresh token will try to grab the token in local storage we go through all that flow again go through all the after request token to save the new token and new access token back into local storage again so that's what happened when the user refreshed so this run right here and then what's next and then you know that in the retrieve token on page load when i refresh the token i set up my off state service so his team might set up my our state right and assume that this success nothing wrong nothing goes wrong the user got a new token then my our state is populated with the right data and if you remember on my off state service there's an is authorized and it's authorized it's actually just if they have token or not and yes they will have token because i'm waiting so this line right here this 34 this slide 34 is actually waiting for this line to set up the off state and then if i authorize if i'm authorized so at this point i have the access token already and my god might have passed all as well right my guard have already passed uh actually my guard have already passed the authenticated guard because at this point i have the token so it passed the authenticated guard and then i have the token i subscribe and i load the permission so the load permission will happen after i refresh the token then load permission will do something else too low permission also set the permission state so you see the pattern here i have a service and then have a stay service for that particular feature so permission i have permission service and then permission stage service we're going we're going gonna go in here in a little bit more i'm gonna go back to our component for a little bit so at this point at this point right i set up permission state i set up permission state and then we're gonna go over the vision guard real quick inside permission guard i use the permission state so if you look into has permission i call an observable on the permission state service so this observable will have to wait for something happening in my state service to actually run so the permission guard will wait for this right so as you say if you have async tasks which i do it will happen at the same time but they can wait on each other the way that you set up them all right so this uh this way i set up them the actually permission guard will wait for the low permission to finish setting up all the permission state before it actually runs his check so i hope that answer the question all right um so back to yeah now we're back to all the permission stuff let's let's look back into the app route so you see my my my route configuration something might not be different than yours and that is the data right here so um the permission based event authorization in this application is done via the data on the route so when you set up a route you can set up the permission to that route and what permission needs is a permission name and what permission required to go to this route so all the route um most of the rounds actually most of the rounds have the read so basically they require you to have um at least the read permission of the decimal managed to go to the dashboard module so what i meant by these two guys i'm gonna write uh something real quick because okay and i don't have the input i don't have the back end so i cannot show the data so when the user actually uh can remove that permission permission service so for for for permission so again as you can see that i fetched the permission on app refresh as well in the app component so when when i first start the load uh permission will be loaded for that user because i waited for that users to be authorized so i only when the the user is authorized i load the permissions and then in here i actually check if they if they authorize that they call the they call it endpoint if not then i just reset the state right i reset the state and the state uh the permission default is an empty array it's going to be an empty array so i reset the permission back to an empty array if they're not authorized so that my app doesn't break uh okay uh to to to go off of if the permission array if the permission array is empty all of my check will actually fail uh fail or false return false so that when the app will just assume if you don't have any permissions then you you don't have permission basically that all right so for for permission client so in here again permission client is a generated class to to call the permission endpoint as i say retrieve permission for user i don't pass in anything here because so here in this retrieve permission will go through the authenticated um uh the authenticate in the sector so it will have the access token of the current user uh append to the headers so then the back end knows oh ciao requests for his permissions then he the backend is going to go grab my permissions and return me so i don't have to pass in anything here then this return we're going to go to that so um uh i love valencia information about permission guard um leaving ask then how can we pass the permission to the permission guard to do the check uh we're gonna go through that we're gonna go through that so this returns me an array of effective permission view model we're gonna look into the we're gonna look into that uh to see what the uh what the kind of model what kind of data that we're working with so here i have the permission id and then i have the activity actually these two are the two that that i need what is the permission id so permission id is actually permission name so if you see right here on my um my file explorer i have a permission name typescript this one is generated by a cli that i wrote so on the back end we have a a table called permissions and this table we have permission id the back end exposes all of the permissions available in the application i don't care if that permission is being used or not as long as it's in the in the database it will be exposed by the backend and you can see this pattern here so i have accounts.manage accounts.manage.api key this means that accounts.manage is a permission particular to the account section of the application so account managed can we create read update or delete so if i have accounts manage permission and i can i can read the accounts page basically that or if i do have a create a create permission for accounts manage or support or let's put into this so if i have accounts managed of i guess 15 let's say let's assume i have that if i have accounts manage permission and the number is 15 the number is 15 this means that i have all the permission i need to do this all right uh to to to work with the account so i can read the accounts page i can create new account i can update existing account or i can delete account so that the accounts manage permission and you can see this right here with the api key so api key is a little bit like five grand a little bit more detail that if i have this then i can update the api key on the account so we we provide api key to like um uh to two clients so they can call our backend so this this is the api key so you can go in here and see all of the permissions that we have in the application and these will correspond to the permission id right so when when we call a permission uh when we call the commission endpoint uh the permission endpoint will return an array of this to to simplify it will return basically an array okay this is a this is a big file you see the 40 40 000 lines mine my webstorm choke i'm going to bring this somewhere else i'm going to put this over to this all right so return an effective permission view model array which is something like that so for permission it will give me the permission id of let's say accounts manage and then my activity will be like 15. so 15 means foreground this is one plus two plus four plus eight that's 15. and i have permission id of like dashboard manage activity one let's see just uh just read then maybe i have permission id of users manage and then activity be zero which means i cannot do anything with user manage or or sometimes in this in this case um in this case we don't really return activity zero if if an activity is zero for a for a permission we just do not return it we just don't return it so now you can see that this is the the chef data the data that uh this endpoint returned then what i do with this data is i call the set permissions in here and let's look into the permissions state right and let's look into the i'm going to copy this over to the permission state and let's look into the past permission so has permissions you saw earlier that recall has permission in the permission guard and has permission return what is actually returned the current permissions and current permissions is the permissions that we set so as i said the guard actually has has to wait for this to be set before it runs so it always guaranteed to have permissions before it runs the permission guard right so the first thing is i'm saying all right uh has permission if i pass in an undefined uh permission and undefined privilege i just returned to so hey you say you want permission but you don't pass me any permission so just say the user can can see it because you don't pass in any permission all right uh here i'm gonna explain a little bit about privilege and the activity so the privilege only has four values one three two four create four for uh update uh for delete and of course it depends on your application if the application needs more then read create update and delete sometimes it is simple as uh you want something called maybe able to export or maybe if able to import right in our case in this application export is the same as read so an import is the same as create or update it depends but if you need an additional privilege you can give you can you can have more than just four but you have to go um you have to go in binary number so this one just do a times two it's actually 16 16. so in binary is it's again is this right um that that and that you see the pattern if you have more you can just do more like maybe even go go up to 32 bits but but again but if if your application needs this much then maybe rolling your own permissions might not be uh sufficient you might reach out to a third-party library or like like off zero to handle the permission for you or key cork so a third party is a key clock or r0 right or something else i don't know i don't know right if you have like a lot of different privilege to check for but in this case i only have one two four eight so i can manage it all right so we passed this um then we go to it we go to this so i'm gonna check the current permission let's say all right current permission i have my permissions i want to return on observable boolean so from an array of effective permission view model i want to return a boolean so i call map so on this permissions i have a sum so as soon as long as so to remind you this permission array is the permissions of the current user so it's all the probations that this user has so that's the permission array then i call sum so as soon as there is one permission of the user that passes these then they're good i don't have to check all the permissions i only have to check one so at least and i find one that passes the the condition then they're good every time that's it so that's that's what some means uh there's every right every is the uh the opposite of some every check for all some only check for one so now the permission so for some i have each permission right now i check each permission i check if the permission if the permission id is equals to the permission to check so at this point i'm checking if accounts that manage is equal to accounts not managed right if they do then i also check now i checked up the privilege so here i'm checking so i say for accounts manager i have 15. so 15 and then the privilege so basically the permission is you need to have the create privilege so basically i pass in so if i pass in account dot manage and then i pass in r2 to create you need to have at least create permission to do this then my my previous e2 so i do 15 and 2 and all of these we have to equal 2 so this is some binary stuff in here and i'm gonna copy this over to uh chrome so as you say 15 is my one two four eight right that's my permission that's my user permission i'm going to do my con user permission equals 1 2 4 8. that's my user permission now i need the page permission the pay permission only two because this page only means the credit right now what i do is you do 15 and two this will return the two because uh because now let's just write the 15 and two 15 is one one one one that's 15. um if i do this correctly two yeah right there so so the binary in binary 15 is one one one one so one one one one [Music] and we know two is zero zero one zero right but if you uh the the the end the this this operator right here this operator actually let me oh my bad so sorry guys this operator is called bitwise and operator you can actually look it up with wise hand and it's right here look look up in the uh ndn so base y ends uh so the n will actually compare the two binary and if if um if both binary at the same at the same like position is true then it is true so let's think of two is one and false e0 so let's let's go through so one and zero so true and false true and fourth would mean false so that's zero right going forward oh true and false if zero and then now we have one and one so two and two each two so that's two and then we have one and zero two and false is actually zero so if we compare if we use the width white ends with the 15 and the and the two you will get the two because that's the that that's the i guess i don't know okay yeah okay yeah you i just i just said that this is the the intersection right the intersection between 15 in binary and the two in binary so now you can return 0 0 one zero and this is actually why we use a binary because we have two and fours in terms of one and zero it only has two values so you can do all kinds of this so let's assume that you have another one so you have now all permission for export import you can just do that without having to have have 15 or 32 or 33 different boolean flags to do your stuff right i'll now go back to the app so at this point so now we just go over the 15 the bit y ends and the two this will return to so to check if they have that permission if they have that correct permission we will say take their permission and the the passed in permission will require permission if that equals to the required permission then yes they have that permission so again i'm gonna show up i'm gonna show one more thing i'm gonna show one more thing now let's assume i have user b permission and this user this user will not have the create so they only have uh read update and delete so 148 so they have 13 right 13 looks big but when you do when you do 13 and 2 it will return 0 because there is no 2 in 13 in terms of binary right even though you say 13 is big but when you do binary uh bitwise n with the two with the create it will return zero and this is true because this user permission doesn't have to create uh required permission that we need so they they don't have permission to access the page that require the create right so so that's the whole binary thing right so again the activity you have a big number of activity doesn't mean that you have enough permission all right so at this point i return i check the permission if it pass or if it fails the permission check and then i take one the reason why i take one because the guard you have to the the stream if you return unobservable in your guard the stream has to complete or as the guard won't run so i have to take one to complete the stream so this has permission has the take one already so it will be completed it will be run when when the current permission has data all right that's my hash permission all right now let's go to let's go back to the route now we know the permission guard calls the hands permission and we know how the house permission is doing the check so let's go back to the route so now on this route i have a can load of permission guard and assume and how um how does this guard know about this information so if you look into the guard the girl has access to uh to the route information and again it has the data right uh so can activate has the activated browse snapshot so this is the route that you want to go to so basically in terms of the guard uh if you go back look look again look back to the route configuration this is actually that next um uh activated route snapshot that the router will pass to your guard it can activate so it will pass all of this information for you so you on on that you have the data right and then you have the permission then connectivity child it's the same thing you have to activate the browse snapshot the same thing if if if if the route has data or the parent of that route has the permission data then we do it then we use it now the can load is what we're using right here so catalog is a little bit different it will give you the route instead of the activity browse snapshot but on the route you have the same thing you have to route the data to permission as well so as soon as you have the uh you have the router you have the activate route snapshot basically everything that the permission guard can provide you so you can put data this data right here on your route configuration to pass in more information if your application doesn't have permission based and you have roadways you can actually put roads in here so basically admin right or manager you can do this and then you have you do the same thing in your permission card but instead instead of checking permission you will check the rows uh permission guard permission guard yep right now i just returned the has permission and has permission just call the has permission on the state service to actually check for permission so at this point i would say does this user have permission if they have if they don't have actually if they don't have permission then i want them to i want to redirect them i have a i have some special case here and you don't have to worry about this i have some special case for this particular application but basically i just want to redirect them to not authorized so you have a not authorized page which is 403 then you have a not authenticated page which is 401 so that's all the permission guard that's all that's it because you set up this already then you set up your stage service so your guard just looks like that now there's one last thing that i want to go over uh which is the directives oh let me show the enum first so the privilege you know so you can see that my one two four eight right and then i have the uh the all 15 just for helper so that so because i want to all because if i want to do permission not all then i can do that so this route requires all permissions basically that you don't have to have it but it depends right now next to the directive so a lot of people uh when when i first worked on the permission stuff for this application i don't have the permission directive i use ngf so i use ngf a lot and then i would i would have something called the enhanced permission blah blah blah blah blah but it is it is a mess and it it keeps repeating over and over so like crap i'm going to create a permission directive and that's what i did so the permission directive is exactly like uh um i like an ngf so instead like mgf i can do permission right and what i take in i type in exactly like um like this so i i pass in let's say on the template i use ipads and accounts.manage.api key and this is actually this is actually a input right a type of text text and then a form control name api key and then i have that right so this is a api key and of course i need at least update i need update to end it for i need update any four so this says if the current user have the update permission of the api key on accounts manage then show this input if not don't show it so it's exactly like ngf right so it's just permissions and also i type in a boolean uh of course so let's say if there's external or additional condition that i want to check for then i can put in here it defaults to you to choose by the way but that building right there so right here i have if value if if i don't pass in anything then yes you have permission right if you don't have if you don't pass in anything right now if you pass in something then i will restructure it so this is my permission this is my privilege so let's just bring this let's just bring this uh down here so you can see right there so permission is this guy the privilege is this guy and then if you if you don't pass in condition like additional condition right here additional condition something else then i defaulted to two then again what i do i just call this the has permission again with the permission and the privilege right here that's it so that's my permission directive is super easy and then my ease condition pass is assigned to the condition now i have has permission and ease condition passed i just do update view so if these are both true which means i have permission and also any condition that i pass in also too then i will just create the view ref which is whatever ngf does this is exactly like ngf and then i also support for the else so you can you can pass in um you can pass in like else no permission and then you can do np template no permission and the template all right you can do this so that's my permission permission directive uh super easy to test too if you want to look into the test um that i'm i'm going to rip out some some stuff here and push into a repo and then i will publish it so you guys can have something to look into but yeah right here is what i do i i test um the directive and that's pretty much it that's pretty much it to be honest so if i don't have any players that use this yet in the code of right here so right here right if they have uh the read permission of schedule manage then allow them to go to and then show the link for them to go to uh account manage yep and uh and that's it that's authentication and authorization in this application that's that's all it's a lot i mean i mean it's hopefully hour and a half just to go through the authentication and authorization uh any question we're gonna take uh two minute breaks we may we might break um we might stop stream in like half an hour so any question at all about authentication and authorization for this app i know like without without seeing the back end implementation it's kind of hard to visualize everything but i just hope that i can show i can show you guys something today yeah yeah you learned something today i hope maybe maybe you learn you learn this or maybe you learn the permission state service i don't know it depends right so those twos are done those twos are done [Music] and then uh take so many a couple of minutes break then we go over to the tnc scolding um uh following uh following us in my command um fun waiting asked is it it's kind of fast uh do you have code to to to review later uh the answer is yes it might not be the whole uh the whole repo because i might not be able to but uh the stuff that i show i will put into a repo and i push it on github and i will publish it so you you will have something to to to watch i mean to see how to read the next topic is going to be oauth and say i don't know again i don't know a lot about security so i'm not sure if i can talk about oauth but i might ask people i might ask people too i i might ask guest speakers to come on and talk about oauth i guess you mean like a google sign-in github sign-in and facebook signing and stuff like that if if that's the case then yes i might be able to go over some implementation but i cannot talk about it like in depth like like this one i don't know enough all right so let's go to tnc scully all right so for people who don't know i have a personal blog is uh narc dot me so n-a-r-n-a-r-t-c it's actually c train uh backwards so knock.me is my personal blog this one is built with angular and scully which is this repo right here and this repo is on github at so github.com the repo for teensy skully and this is the block and i just want to show up something uh go to lighthouse generate report if you build your block with scully you will get something like this that because i'm streaming so it might affect performance a little bit but usually i get a hundred across except for seo i'm not good at accessory at all so i'm gonna talk over uh scully a little bit so let's walk over uh scrolling uh the blog i have uh dark theme uh live in uh i have about me system route here and some tag page here so then i have the actual blog page with um with codeblock with uh markdown and stuff like that all right and comment and of course you can go to how you can go to these as well yeah all right back to uh back to the code so again this is a scrolling application so right here in my package.json i have some scully oh i should just put scully.io this is the homepage of scully uh you can you can go through the document documentation to get started uh really quickly um to get started really quickly yeah it will it will set up the actually you have to have an angular application and then you run that ng ad scholarly it will set up your application your angle application into a skully application with these dependencies next it will have a skully config file so this file will tell scully what to do uh here is what you set up some plugins so basically for the routes so for my blog route i want to re-render pre-render uh the the the the block route right so i just say hey for this route look into the folder block so if you look into the folder block right here you will see that i have all the markdown files so skully will look into him and we find these files and then it will run is its own thing to do to read to read this markdown file and turn that into html page for me so if you look into my desk look into the static and the blog so you see that right it will return me the index.html from from this all right so that that's that's that's the basic of scrolling now let's go into the code uh really easy so first thing first of course the route routing configuration so for routing i have if you go to north dot me i'll use just below the home page the blog will reload the blog page at the blog module the tag will load the tag module and then they have to not file component so narcotic component is just basically that that's my not file a view model say the globe keynote [Music] so when asked i have a question i have unrelated question so when do the js files of the service of the interface of the enums or the view models will be loaded okay they will be loaded in in the files that you imported into and as soon as that file is loaded they will be loaded so when um like webpack i'm talking about webpack right here so webpack bundles all of your files and we put all the imports of one file on the top then you know javascript just go from from top to bottom just go through top to bottom let's say you you hit you hit the module and then the module have have the uh the class service class imported it will it will go ahead and load that service that the service class that you export so this is why we have all angular has the provided in root so assume let's assume i have my app module here and app module will always be reloaded first because it gets referenced here in demand and man will we will read first all the time right so with that information you know that app module will always load will always load so before i think before angle 5 or angular 6 before the provided in so if you don't know what i'm talking about you know they provided um the injectable provided in root right here so before before we have this if you want to buy some service at the top level we have to put that service inside of the provider array of the app module so let's say our service here right and this requires to import the import vr service right and because app model is always loaded so it's all so that our service will always be loaded right now with the provided in root we don't have to import our service anymore so our service technically is not loaded along with app module let's see if i have any service in here um service yep right there so technically this meta service is not exported anywhere yet it's not exported in the app module so as soon as we import or we inject the magic service somewhere like in my home component then the meta service will be loaded so assume that this home component is lazy loaded down way down the road and meta service is only used in here so meta service is also lazy loaded again along with the whole module so that's that's the whole reason of the provided in route so they provide you a way to lazy load service that's one that's one thing another thing is when you lazy load your when you lazy load your module like this one we we don't import home module in the app module anymore because if that's the case if we import home module here then it befits the purpose of lazy load because it will be loaded along with app module right so we when we lazy load things we do not import we do not put the module in the imports array because we laser load so that that's that's the that's the main uh i hope that answers your questions right i'll go back to scrolling so very very uh very standard java angular so in my app module it will have the scully lip module so this one is added to you by the ngs skully schematics so you don't have to worry about it so if i import module a into many different modules then it will increase the bundle size or the webpack only loads module 8 once then when the other modules need module a webpack will give that module a to that module so to answer this question it's actually only load once assuming i'm gonna i'm gonna write right here so assume you have uh angular has four modules so far motion correct and then you have a laser low a model and laser load b module say you want to use forms model in a model so in a you will have this b you do not when you lazy load so so at this point webpack knows webpack or angular cli knows that only only lazy low a module needs the forms module so it will grab the bundle size of the forms module included inside of the a module so now you will see like lazy low a chunk with like let's say 500 kilobyte and then laser uh load dot jump is like 100 kilobytes so this one is one hundred plus four hundred by our forms assuming let's assume right so now this is the case and then you ask now if i want to use forms module inside of lazy load b module then you have to do this right right then now you have to do this but now webpack or angle cli knows oh this do means forms module in two places so now we're going to webpack will will separate the forms module into a common junk this is from model and assuming this is 400 kilobytes then it will take off the forms module from the formula from the a and from the b it will load the common jump for you so it only loads once all right i hope that answers the question again great questions great questions thank you uh all right so we're back to scully lip module and then i have a service worker i have service worker um because i have like um if i purchase new stuff to do to the uh if i deploy new new stuff to the blog uh then yes uh i need the service worker i'm gonna show you where i use the stuff is working i'm going to go through this real quick so look look into the home so the home page is this home page will will have this avatar space and they have a blog list so if you look into the home they have about i have the blog list then i have a list of components so the the if you look into the component html you will see that this is my left side so that's my left so this is one right here so i have my theme toggler so this uh this is my theme toggler right and then i have my avatar and i have my info i have my navigation so this is my navigation i have my socials right here is my social account and then i have copyright which is this guy's right here so that's my copyright and then on the right hand side i have my router outlet so right here i have my router outlet so i render my about right here so you can see that the dsi class i mean the aside element is still there on the block list and here the about me change so that's my router outlet so let's look into the avatar so this is where i'm using that service worker right here so i wish i could make something let's change something real quick let's do my text type global bonus chest let's do let's add angle bit now in my copyright build with reserved so let's do angular vietnam let's do that and i'm going to push i'm going to push and angle it down to copyright can i kind of talk about can you talk about the theme toggling yes i will talk about it and then i think that's the last thing that we'll talk about because the stream is like two hours all right now i'm pushed uh i have i have my vlog hooked up to netlify so as soon as i pushed it will stop building start building and then we would now if i go to my let me go to my blog right here i have my blog still running right here you don't see the angle of vietnam right now it's building i'm gonna let it build for a little bit then i'll go back to my code uh back to the avatar component so here i'm just saying hey if if um if there's uh if there's service worker enabled then i'm gonna do all this thing so what i'm doing is i say hey fraf application ref is the like top level of your application even on top of the app component so application graph is actually what running all the chain detection so we're going to talk about like application rev in the future stream when we get into more angular stuff but right here just say hey application graph so basically application when you stable let me know so when the app is stable when it blows all all the stuff that it needs to to load and then i have the interval of every five minutes and so it's just an interval right here and say every five minutes and then i have a stream called every five minutes after the app is stable so i concat the app is stable so app is stable it has to be it has to run first and then every five minutes so let's say let's think if if app is stable it's not stable until six minutes then this will not run so that's the that's the main thing right and then i have i subscribe to the stream right here so basically the stream will run at each label and then every five minutes it will it will emit every five minutes of course i have to destroy it and then every five minutes i will check for update right this will call check for update that's it i will call check for update and check for update internally will actually uh emit something through the available observable right here so i have has update i listen for the available uh listen for vote for the available right here and then map2 so basically if i have available stuff which is true if i have available if i have new stuff available then it's true then it has update and start with false so by default it will it will not have update then as soon as i have update based on this i map it to true then i i [Music] subscribe to it using the async pipe right and then i have these classes on my vm has update so basically i show i have a class show on my avatar if has update is true and then i have cursor pointer it has a baby's true and then on click i will reload the page so if i have update if i have new update i want to reload the page so now let's go back to the blog it has been published so the product has been deployed if you look into the blog you will see that nothing nothing new yet nothing new yet right but if we wait a little bit if we wait a little bit again wait for five minutes maybe then you will see that my um actually let's just go to a new page oh right you see i go to not me i don't have the angle of vietnam yet so i want to go to north dot me because i said i have service worker so service worker will load the cache version of my blog and then this is the service update service and say hey i have the new version now all right because not because netlify has my new version the service worker while it's load cache version for me will actually reach out to netlify to grab the new version and then it compares the new version and my my old version my current version that it's showing then if it's different then it has update so this is basically check for update does if i have a new update i will have that right now i can just click on here to refresh and now i have the emulator vietnam so now my my blog has a live refresh when i deploy a new version using the service worker so that's what i want to uh to point out all right now i'm going to talk about the theme toggling a little bit so for theme probably to work um you have to set up a little bit of of of of a variable so if you look into my code and if you look into uh the styles there's a custom tailwind base if you look into that you see i have i have my root this root right here is the selector on the html root so it's on top level and then on theme dark then i have these values on thin light and have the same value i mean the same variables but with different values right i have these classes film dark and theme light right and um i believe on my body on my website service right theme service so on on theme service i have um basically a theme service right update right here so [Music] uh when i when i add um when i change the theme i will actually change the class on the document body so if you look into the dark body right here so you see that i'm i'm a thin dark but when you toggle it go to thin light and it's on the body and on the because i set up all the styling right here on the different colors right here it will just take over because my application look back into the styles my application everywhere i use color and and and stuff based on the theme i will use the uh variable and i'll read that background color or the text color from from these valuable right here so when i change when i have the thin light my background color is white so that's my background color if it changes back to dark my background color is not this this dark color so now my uh my body will have that uh that color so that's the whole theme toggling stuff and uh by the way use the renderer uh use the renderer uh right here actually uh i use the renderer factory because skully does allow you to to run the angular application without javascript so that's why i need the renderer factory but you can just have the renderer so you can just do renderer to that you can just do that right without the factory and use the renderer to add class to the document body with the with the correct uh class dark or light it depends that is the theme power all right i think that's it uh we don't have time for for miscellaneous stuff but i think that's a lot of information for today's stream so i'm gonna stop sharing then we're gonna have some last question last minute questions so far uh so i'm asked when you have more free time please continue working on the end of 100 days yes that's still on the about my point but i've just got a new job not just like five weeks ago a month ago so i'm still trying to get used to the new job so i don't have a lot of free time and i'm also expecting a new baby so i'm going to be a dad that too so of course when i have more free time then i'll continue doing that thank you all right uh if there is no more questions then i'm going to stop this stream and see you in the next [Music] one you