What's going on guys? Assalamu alaikum. Welcome to Amigos Code.
In this video, you're going to learn pretty much everything you need to know about JWT using Spring Boot three. So about three weeks ago, we posted a crash course on spring security and there was a lag with JWT section. So we decided to rerecord the entire section and actually make it so extensive.
This crash course right here is brought to you by Aliboo. and is the one that led the spring security. So go ahead and subscribe to this channel.
Show some love because it's going to be bringing you awesome content like this from time to time. Security is a must when designing and building APIs. And it's really important that you understand JWT so that you can secure your APIs before we crack on. Literally just take one second and smash the like button. Also, if you're new to the channel, subscribe.
And if you haven't joined the private Facebook group as well as Discord. Go ahead and join because the community is growing and we're waiting for you. So without further ado, let's kick off.
I just want to say that you can grab the entire source code and the description of this video so that if you have any issues or you want to take what you learn from this course and then apply it within your own API. you can do so feel free to clone the repo and yeah just just use the code as you intend and if you have questions regarding jwt literally just ask on the community and someone within the community will be able to help you before we start the implementation process let me first explain to you how this JWT validation mechanism works. The whole story starts when a customer and a client send an HTTP request to our backend system which is running using Spring Boot Container running on an Apache Tomcat embedded server. So just a reminder for you the first thing that gets executed within a Spring spring application is the filter so anytime and each time you create a filter just notice and remember that it will be the first thing that gets executed within our application so in this case the first thing that will be executed is our JWT authentication filter and this is only a once per request filter and has the role to validate and check everything regarding the the token or the jwt token that we have so now let's start the process the first thing that will happen we will have here an internal check to check if we have the jwt token or not so if the token is missing as we can see here we will send a 403 response to the client so and the reason is this missing jwt all right so now we have our gwt token and then after that we will start the process or the validation process so this validation process will start in this way so the filter like the internal execution will first make a call using the user details service to try to fetch the user information from the database and this we will base on the user email that we will set as a claim or token subject that we will extract within this JWT authentication filter so I repeat again this JWT authentication filter will check the JWT token extract the username or the email or we call it the subject when we talk about JWT tokens and it will use that email to fetch the user details information from our database okay so this is the first goal Then once the user is fetched we have the response from our database and the response can be either way can be existing user or non-existing user okay so once we get the response to our JWT authentication filter here we will make a few checks which is if the user does not exist we will also send a 403 to our customer In case everything is fine and we get our user from the database, we will start then a validation process. So this validation process, because this JWT token was generated for a specific user, so we want to validate this token based on the user.
And here we have this validate JWT process or mechanism, which we'll try to call a JWT service. And this JWT service will take as parameter the user itself and also the token or the string token or the JWT token. Call it whatever you want. After the execution of this validation process, here we have two case scenario.
So the first one, the token is not valid. So it's not. So, for example, the token is expired or the token.
is not for that specific user so what we do we will send also a 403 back to our customer so and the reason will be this invalid jwt token otherwise what will happen we will call or we will update the security context holder and set this connected user because when we fetch the user details information from the database we will be able to set this security context holder so we will tell spring or we will tell the set or the rest of our filter chain that this user is now authenticated and we will update the authentication manager so every time we check if this user is authenticated for this request the answer will be yes once the security context holder will be updated it will automatically dispatch the the request and it will be sent to the dispatcher servlet and from the dispatcher servlet it will be sent directly to the controller we will do all the execution that we need to do for example calling the service going to the database and so on so forth and then we will send back a response for example it can be a jwt and it will be http 200 or whatever any process that will get executed within this controller So this is how JWT authentication mechanism works. Now let me show you how to implement this and how to realize these steps. Let's first start by creating a new Spring Boot project. To do so, the recommended way and the way i also recommend is goey is going to start.spring.eu which is the spring initializer and create a new project from that so first of all make sure you want you use maven this is what i will be using in this video and tutorial then we want to use the recent version of spring boot which is now 301 okay and also here make sure you select java 17 because the minimum required version which is compatible with spring 3 is java 17. next select the jar packaging and now let's fill this project metadata so for the group id i will call it com.alibu and the artifact i will call it security okay so i will leave the rest as it is and now i will move on and add some dependencies so first of all we need the spring web because we want to expose few endpoints we need also the security and this is the main object of this video and then we will need jpa or spring data jpa because we need to manipulate and interact with the database then we need a postgre sql driver to connect to PostgreSQL you can also use any other SQL database like MySQL or Oracle or whatever finally we want to use Lombok to reduce the boilerplate code so now we have our project ready we can just go ahead click on generate and start coding As I mentioned before we will be using PostgreSQL as a database for this application. So let's first start by configuring our data source.
For that I will be using NTDJ and I will use this database tool. So this one is available only with the ultimate version otherwise if you don't have the ultimate version just make sure you are start PostgreSQL and you can use the pg admin or you can use the dbiver tool to connect to any data source okay so let's start with that click on here and then we have this plus icon so click on this plus icon and then we want data source and then filter for postgre sql click on that and to be able to connect So make sure here if this is the first time you will have instead of driver post degree SQL, you will have a link or you will have a button here to download the driver. So just go ahead and click on it and download the driver. Next, the host is local host because it's the local one. And the default port for post degree SQL is 5432. Then if you create when you created your PostgreSQL did you mate or did you choose a username and password if yes so just go ahead and specify them here so for me for the purpose of this tutorial i made it amigos code and for the password it's just password okay and then once you fill all this information just to check if everything is working fine click on this test connection and make sure you get this succeeded otherwise just check your configuration all right so now everything is done i will go ahead and click on ok and the first thing that i will do is i will create a new database so right click on this data source new and then database so i will call it jwt security and then hit ok so the first time it will not be automatically shown so just click here on this two of eight the number the numbers may might change from one laptop to another and here i want this jwt security okay so uh open it in here and here we can see that we have zero of three schemas just select the public one because this is the one we need and this is where we will find all our tables once we create them.
So now we have our data source available. Let's move on to the next step. Now let's establish a connection between our application and the database we just created.
So the first thing to do is go here to this application properties. and rename it and use the representation YAML. Okay, so this is what I prefer personally, and you can keep properties if you want to. But to better follow this tutorial, it's better to transform it to YAML. So in order to connect to a database, we need to provide a bunch of properties right here.
So we will start with spring and then data source and one of the of the things that we need to provide at first is the URL and this one is the URL or the connection string to our database if you don't know it just go here to this database click on it right click on the the connection you just created properties and you copy this one you copy this part right here it's gdbc colon post degree SQL and then the address port Slash the database. So let me close this. I will paste this one and make sure here you write the correct database name.
So for us, we call it JWT security. Now we need to provide the username and password. Okay, so for my case, it's empty.
Make sure you provide the correct one. And here it's password. So next property is after providing the data source information we want now to give some other JPA properties okay so here it will be JPA and then hibernate and here I want to tell spring what to do at the at the startup or update application startup and this property is the DDL auto and here we have a bench of options so we have create drop create none update and validate so I will be using the first one because every time I want to start the application I want to create a new database a new schema and when I stop the application I want to destroy it okay so I always want to start with empty database all right so the next one you within jpa within jpa like you see now you need to really pay attention about the indentation right here because this one this tdl auto is part of the hibernate and the one i will write right now is part of jpa so it's spring jpa and then show sql i want to show sql when when we perform or when spring data jpa performs a query I want to see that query okay I want also to add some other properties so here I will type properties and one of these properties and here I have hibernate and within this hibernate I want also to format the SQL so format SQL true I want my queries to be formatted now go back to the same level as properties and provide some information about the database so here we want to tell jpa which database we are using and for this case we are using postgreSQL and then we can also provide the database platform that we are using and this will help spring performing and writing the better queries to to suit our postgreSQL database so for this one it's org.h hibernate dot dialect dot post degree sql dialect all right and here we just forgot one property right here which is the driver class name so this will help spring to detect or use the best driver class name and here we are using post degree sql so until ej will automatically proposed to you otherwise it's the org.postgreSQL.driver and this is the one that we got from the postgreSQL driver dependency.
Alright so that's it about this configuration let's move on and start implementing our security. When we talk about authorization and authentication we mainly talk about users so let's go ahead and create our user class so within the java package and within the main package that we have right here right click and new class and here we can create a package and a class at the same time so the package i will call it user and here i will just call the class user so user.user will create a package user and inside of it it will create a class user all right so this is our user class let me make this one full screen and now i want to write a bunch of properties within this class okay so my user has the following characteristics or the following fields so first of all i want to have an integer id and then i want to have a string first name and private string last name. And also of course, we need an email and password for this user to be able to authenticate and connect to our application. So here I will add email and also private string password.
So these are the information about our user. Now I will add a bunch of Lombok annotations in order to reduce the boilerplate because you know when we create a class we need getters and setters we need constructors we need also the design pattern builder to build to be able to easily build our object and so and so forth so let's start with that so we will need the date annotation and this annotation will provide us with the equivalent of getter setter as you can see here so it generates getters for all fields for useful method methods to string and so on so forth so it's the equivalent to the getter setter required as constructor to string and equals and hash code okay also I want to use the builder annotation so this builder annotation will help me build my object in an easy way using the design pattern builder okay and also i will need the no arcs constructor and of course when we talk about design pattern builder we need always the all construct the or arcs constructor okay so let's add this one and like this we have our we have our user class now let's make this user class an entity To make this user class an entity, so the first thing we need to add is this entity annotation. And since we are using the Spring Boot 3.0, here make sure that the package is Jakarta.persistence and it's no longer JavaX.persistence. So this also will help you tell if you are using the correct version of Spring Boot.
So here we need the entity annotation and... And because this username, this user class is already reserved for PostDegreeSQL because PostDegreeSQL already has a table called user so we cannot create a second table called user. I will use the table annotation right here because you know the table annotation if I do not provide, if I don't provide any name right here it will take the entity or the class name as a default name for the table okay but here i want just to call it underscore user to avoid this ambiguity between this user class and the one with and the one with post degree sql so now this is kind of sufficient to tell that this user class now is an entity but we still need to provide one small information okay so here we have this error right here we see that this persistence entity user should have a primary key okay so we need to add an at an id attribute which we already have right here but we're still missing this id annotation so this id annotation it's coming from the jakarta.persistence and it's telling that this id is the unique identifier of this user class now i want also this id to be auto incremented or auto generated so every time i want to create user i don't need to provide this id and every time this id is null i want it to be auto incremented by the system or by spring data jpa itself so to do so and to make it in an easy way i will use the annotation generated value okay so this generated value it will make this id or this object auto generated using whether a sequence a table and so on so forth and we call this a strategy so for this strategy we have we have several options okay we have auto identity sequence table and u ui id so the auto is the default value identity means that it will use an identity number like an auto increment Sequence means that we will create a sequence within our database and use this sequence to increment each time the value of the ID. The table, this means that we will create a table in the database and we will call it, by default it's called HibernateSequence.
And this table will always be requested and queried by Spring Data JPA to get the last value and incremented for the last one. The UUID is using this one. I think you know it from the Java utilities.
But if you leave it to auto, if you leave the generation type to auto, Hibernate will try to detect the best suitable option for you. For example, if we are using PostgreSQL, it will pick by default sequence. If you are using MySQL, for example, it will pick table because my sql does not work with sequences so it will it will pick table for that so for the moment i will just keep it empty like this because as i mentioned the default value is auto so it will be automatically detected okay so now we have our entity let's try to start the application and make sure that we have our table created within the database here enable the annotation processing for lombok and now we have our application started let's have a look quickly on the logs and here we see that create sequence user sequence start with one increment by 50 this is automatically generated as i mentioned and here we see the sql that we have create table user with an id email and so on so forth okay And here we have spring security is auto generating a security password.
And this one we will see later on. Okay. So also, if you want to check, you can open your database right here.
Click on this one, refresh it. And within the public schema, we see that we have this user table right here. And if we open it, we will see the ID or the attributes that we already provided. When Spring Security starts and set up the application, it will use an object called user details.
And this user details is an interface that contains a bunch of methods. Okay. And each time you want to work with Spring Security, you need to ensure that you are providing this user details object in order to make Spring Security life easy to use. Okay. So to do this for us, for our user, I recommend this way.
So every time you have a user, think always to make it or to implement the user details interface. So like that, your user or your application user is already a Spring user, if we may say so. Okay.
So to do that, just go ahead to this user class that we created and implement an interface called user details. Okay, and this user details is from the package org.springframework security core user details. Okay, click here and now it will ask us to implement a bench of method. So click on this one, implement methods.
And we see right here that these are the methods that we want or that we need to auto generate. Okay, not auto generate, but we need to implement. So it's get authorities username and we have this boolean methods account expired, locked and so on and so forth. OK, so just go ahead, click OK and we will see how to override. But before that, I want to go a bit a bit more into details about this user details interface.
So I will open the definition, download the source so we can easily see it. So. Here, if I click on this icon right here to see all the implementation of this interface, we have this mutable user, mutable user details, and so on and so forth.
Also, we have our user class, the one that we created. We can see also that we have this user from Spring Framework Security Core user details. Let's have a look on this one.
Okay, so this user detail contains the username, password, authorities, and the... bunch of booleans the account expired locked non-expert and enabled or not and this information or this uh these attributes spring will use automatically to play with authorization and authentication and for example if we we can rely on this account non-expired for if we want to have some expiring dates or use the user can expire and also if we want to lock and unlock the user or the same if we want to work with credentials and so and so forth okay so i will i will give you the time to play and check this and here we see that we have a bunch of constructor and we have these methods that they need to be overridden right here okay so here we see that this user already implements user details so for you you have two options whether you implement this user details interface within your user class or you can create for example a user you call it app user and then extend the user the one from spring boot so it will be the same but for me i want always to have control over my object so i create my own user class and implement user details so now let's go ahead and implement this method. Okay.
So here the first one is we need to provide a collection of granted authorities. And already the method is called get authorities. So this get authorities will return or should return a list of roles.
Let me explain it like that when we talk about roles. So here we need to add a role. Okay.
So I will do. or i will create a role and this one it will i will create an enum for it and i will call it role and this let's create this class and here you can choose the option create enum role hit ok and we want to create it within the same package and within this rule it's so easy i will just user and admin okay so We want to have only two roles within our application. So now we have this role and because it's an enum, we need to add this enumerated annotation.
And this enumerated annotation is to tell Spring that this is an enum and we want to use it whether the enum type ordinal or string. So by the way, by default, it's ordinal means it's 0, 1, 2 and so on and so forth. String it will take the string value of of the of the ina.
Okay, so let's go back to this get authorities so in here because With our design which we said or we decided that the user can have only one role So I will just return a list Dot off and here I want to return a new simple granted authority Okay, so the object that they want to return is called simple granted authority. And here I want to return the role dot dot name. Okay, so the role is referencing this role right here.
Next one is this get user name. So the username for us is our username. So it's the email.
Okay, then we have this account non expired. So here we have this is account non expired here make sure and be careful it's non expired false this is the negation so non expired should be true otherwise we will not be able to connect our users. So non expired non locked and non credential on expired and if the user is enabled false and here I want to make it true. Here there is one thing that I need to mention right here So within this method, let's go back to this user details interface. We see that we have this get password.
Okay. But this get password was not overridden right here because we have this string password right here. And we have the Lombok annotation.
So we have already the method called get password. But here if I just name this one we see that we will see that here we will automatically tell that we want to override this method okay so let's override it just to be to be more visible or like better visible for you i will rename this one to password and here for this password i will just return my my password okay so i just wanted to mention this one so in the next time or like when you have a different name for this password field you don't get surprised when you see this get password or when you have this password exactly like that and you don't see it so now you know the reason why okay so now we have everything we need within our user details so we created a new role and we overridden or we defined all the methods that are required by spring security now our user is ready so let's move on and create a repository for that user class so the repository is the class which is responsible to communicate with the database so when working with spring data jpa we don't need to create a class all we need to do is create an interface and let's call it user repository and this user repository to make it a repository all we need to do is to extend another interface called jpa repository okay and as you can see here this jpa repository is from spring framework data jpa and so on so forth and it's a generic interface that takes a t so which is the class and an id which should be the id of our user class so let's use this one and pass these types so this the user and we used integer as an id so let's pass integer right here okay so now our repository is ready and as you know the spring data jpa has also a bunch of methods or ready to use methods like save find all find by id and so on so forth okay now i will create one method that we will need later on and this method will will try to retrieve or find a user by email because email is unique so we need to find or we need to fetch a user by its email. Alright, so I'm gonna create this optional user and like optional is a generic type so it's an optional of user and here I will use the query method provided by Spring and I will use the method findBy and here all you need to do is providing the attribute or the field name that you have within your class.
So for our case, it's email. For example, if you use username, just find by username. And here, all I need to do is to pass a string email. Alright, so this is it.
Now we have our repository ready to use. Let's move on to the next steps. When we when we check again our schema right here and the architecture that we have right here so we see that the first thing that we will get or the first thing that will intercept our http request is the jwt authentication filter so let's go ahead and create this filter so here within our base package right click right here new and I will create a new package I will call it config so I want all this to be part of my configuration package and I will create a JWT authentication filter I will call it like that so this is our authentication filter class and now in order to make it a filter we have multiple options okay but here As we can see in the schema right here, we want this filter to be active every time we get a request.
So every time the user sends a request, we want our filter to get fired and do all the job that we wanted to do. So this one, we need to extend a class called once per request filter. And as the name indicates, it's it will be a filter by one every request so let me download the data source and you can see here once per request filter extends already generic filter bean and this generic filter bean already implements the interface called filter so for us we had two options whether using or extending this once per request filter or implementing the filter interface right here so it will be the same but let's use something already provided by spring so it's better to use the ones per request filter so now let's implement the methods and we see here that we have a method called do and filter internal and we have three parameters the request the response and the filter chain let me explain each part of it i will just align this parameters right here so you can see all of it So these are our parameters.
So here what we have, we have this HTTP serverlet request, the response and the filter chain. So the request is our request. And the response is also our response.
So we can intercept every request and make an extract data from, for example, from the request and provide new data within the response. So for example, if I want to, to add a header to my response we can do it using this once per request filter okay and the filter chain is the chain of responsibility design pattern so it will it contains the list of the other filters that we need we need to execute so when we call this filter chain dot do internal filter or do filter it will call the next filter within the chain so here i want just remove this this warnings so because this these three parameters they should not be null and to do so i will just add this non-null annotation the one from spring framework.lang and i'm gonna copy paste it and move it and put it in here okay so like this we no longer have this warning you And now the last thing to do before moving on and start implementing this last thing to do is we need to tell spring that we want this class to be managed bin or to become a spring bin. And to do so, we need to annotate whether with service annotation or component annotation or also repository.
It works because three of them are the same annotation. The repository and the service, they both extend the component. But i will just make it a component right here and also i will use another lombok annotation which is the required args constructor and this required args constructor it will create a constructor using any final field that we declare right here so for example if i use if i do private final string my string this annotation it will create a a constructor using this private final field. Okay, so now we have our filter ready to use. Let's now start implementing it part by part.
From this diagram right here, we see that the first thing that... gets executed or the first thing we do within this JWT authentication filter is checking if we have the JWT token. Okay, so let's move on and implement this. All right, to do so within our method do internal filter, let's try to perform some operations.
Okay, so first of all, I will create a string, I will call it authentication header. right why because when we make a call we need to pass the JWT authentication token within the header so it should be within a header called authorization so what we need to do here is create is try to extract this header okay so this authentication header is part of our request and from the request we can call a method called get header and within the header we can all we need to do is to pass the header name so our header is called authorization like that so this is the header that contains the JWT token or the bearer token we call it also bearer token okay alright so now I will create another variable let's also make it final string I will call it JWT or JWT token, call it whatever you want. so here i want to implement this check that we did before so we we talk about here we talk about this check jwt token so let's go let's implement this so here the test that i want to do is if the author authorization header is null so i want to do an early return or if not my authorization header dot starts with because as I told you the beer token should be always or should start always with the keyword beer okay and it should be exactly like that and then we have a space so if we don't have these two conditions all I need to do is call the filter chain dot do filter and I need to pass the request and the response to the next filter okay And here, don't forget to call the return semicolon.
So we don't want to continue with the execution of the rest of that one. Okay. So here, this is the check that we implemented. Now, let's try to extract the token from this header.
Okay. From this authentication header. The next step is we created already a JWT.
variable now I want to extract this token from my authentication header or from my authorization header and I want to do a substring starting from the position number seven and why position number seven because if we count this beer with this space the count is seven okay so let's move on and check what we need to do next After checking the JWT token, what we need to do is to call this user details service to check if we have the user already within our database or not. Okay, but to do that, we need to call a JWT service here to extract the user name. All right.
So let me show you what we need to do. So right here, I will just go back and create a final string. username or email call it whatever you want so I'm just gonna call it user email okay to be consistent and avoid confusions so I will call it user email so after extracting the JWT token what I need to do is I want to extract also this user email so this user email equals and here I will add a to do extract the user email okay but to do so I need to extract it from let me add it here from JWT token so to extract for this user email from the token I need a class that can manipulate this JWT token okay so let's try now to implement this class this class I will call it here I will just create my class here, private final, I will call it JWT service.
So I don't have yet this JWT service. But within this JWT service, and what I want to do here, I want to use a method that I will call it, for example, JWT dot extract username. Okay, so let me call this JWT service dot extract user. name or user email okay let's keep it username within the JWT because mainly with spring security we talk about user names and to extract this one I need to pass the JWT as a parameter okay so I will create this class now I will ask until you to create this class JWT service and I will create it you can keep it whether with the config with the config package or you can move it to a different one so i will keep it within this package and also do not forget to add this service annotation to make it or to transform it to a managed bean all right so now i will just create this extract username so create method extract username in jwt service and yes this is what i want to do i need a method that will return a string username and it takes as a parameter a string token or string JWT okay so let me call this one token I think it would be better as a name and yeah that's it so I will just return null for the moment and let's move on and I will show you how we can how we can implement or how we can extract this information from our JWT service So now in order to be able to manipulate JWT tokens, generating one, extracting information from the token, validating the token and so on so forth, we need to include new dependencies within our application.
So let's go open our pom.xml file and here within this pom.xml scroll down and go next to the Lombok or post degree SQL dependency. And here, just add a new dependency and this is the first one called JJWT API dash API and it's from a IO just dot JSON Web token okay and the recent version at this time is the 0115 so let's use this one we need also to add another dependency which is also from the same artifact or from the same group ID but it's a different artifact So we need the JJWT implementation. So it's called JJWT AMP. And from the same group ID, also the same version, you can extract this version to a property and use it from there. And next we need a final dependency, which is the JJWT Jackson.
Okay. So also from the same group ID and the same version too. Now, once we add.
or once you add these dependencies or any dependency to your pom.xml or if you make any updates to your pom.xml make sure you click this button load maven project but also if you don't see this button just right click inside the pom.xml file maven and then you have the option reload project okay so until ej will download all the dependencies and add them to the to the class path all right so our dependencies are ready to use now we will go back and implement this JWT service. So before we go and implement all the services and dive too much into the code, let's first try to understand what is a JWT token. So a JWT token stands for a JSON Web Token.
which is a compact url safe means of representation of representing claims to be transferred between two parties the claims in jwt are encoded as json object that is digitally signed using a json web signature okay so the jwt consists of three parts so here we have the header we have the payload and also we have the signature so the header typically consists of two parts the first one is the type of the token which is JWT and the signing algorithm being used such as for example HMAC or SH-256 or RSA okay the second part of the token is the payload which contains the claims claims are statement about an entity typically the user and additional data. So as we can see here, we have the subject, we have the name, we have this IAT, we have, we can have also extra information like authorities or extra claims right here. Okay. So there are three types of claims registered, public and private claims. The registered claims are a set of predefined claims which are not mandatory but recommended.
to provide a set of useful and repeatable claims some of the registered claims are is are iss or the issuer we also have the subject the the odd the x exp like the expiration time and so on so forth this we will see when we will implement the token generations okay we have also the public claims which are the claims that are defined within the ia and a json web token registry or public by nature private claims are custom claims created to share information between parties that agree using them okay the last one or the third part of the token is the signature which is used to verify the sender of the jwt is who it is claims to be and to ensure that the message wasn't changed along the way okay so now let's move on to the code and see how we can generate or how we can extract claims from this jwt token okay so also within this jwt.io website you can play with the payload you can add some information here and as you can see everything you add some every time you add something you see that it changes right here okay let's move on and go back to our code Now before start implementing this extract username method I want to implement or write some code to extract all the claims and also another method that allow us to extract one single claim. Okay so first of all I want to create this method I will it will return a claims and these claims if you if you see right here when you click on import class it's the one from io.jsonwebtoken.claims it's the dependency that we just added so these claims i will call this method extract all claims okay so this extract all claims of course it will take a string token as parameter and now i will show you how to extract this so to do it we need to return our jwts and this JWTS is also from the IO.JSON web token and we need this JWTS.parseBuilder and in order to parse this builder or to parse the token and here we need to set the signing key okay set signing key because as we mentioned before when we try to create to generate or to decode a token we need to use the sign in key so I will here just let call this one get sign in key and I will explain it later on we will implement this method and then we need to build because it's a builder and once the object is built we can call the method parse claims jw jws okay so this one this method parse claims jws so we want to parse our token and once the token is parsed we can call the method get body okay so within the get body we can get all the claims that we have within this this token right here all right so now now before we implement this signing key method which should return a key as you can see in the definition here so this one let's first understand what is a signing key okay so in the context of json web tokens a signing key is a secret that is used to digitally sign the jwt the signing key is used to create the signature part of the jwt which is used to verify that the sender of the JWT is who it claims to be and ensure that the message wasn't changed along the way. So we want to ensure that the same person or the same client that is sending this JWT key is the one that claims who to be.
OK, so the sign-in key is used in conjunction with the sign-in algorithm. specified in the JWT header to create the signature. The specific sign-in algorithm and key size will depend on the security requirement of your application and the level of trust you have in the sign-in party, okay?
So here, in order to do that, first of all, we need to go ahead and generate a new token or a new signing key or a secret, secret key, okay? So... to generate this secret key we can do it online because now we like for security reasons we need at least or like the minimum a signing key of size 256 okay so and in order to generate a key so you don't need to worry about this there are so many tools and online tools to to do this so here i will just go ahead and create a private static final string I will call it secret key and this secret key equals the value that i will generate right now okay so now go to the browser and navigate to this address which is allkeysgenerator.com and then slash random slash security encryption key generator dot aspx okay and we have here encryption keys and here we have also the security level so as i mentioned the minimum required for JWT tokens is 256 bit. Okay. And then click on this checkbox.
Yes. The eggs make it check it and make it. Yes.
So we can get this eggs, eggs, secret key. Okay. So if you need more security, just go ahead, change it and do like you can go even up to two.
4096 bits. Okay, but for now, for the sake of this tutorial, I will just make it or leave it to 256 bits. Okay, now let's go back to our code and paste this code right here or this key right here.
Also, you can move it to the application properties and use it from there. All right, now let's continue and let's implement this get signing key. So, here i will use intelligent to auto generate or to create this method so i will ask him to create this method and this method should return not byte but it should return a key okay so now to do this first of all i need to create or to make an object or a variable of type byte i will call it key bytes and this one equals decoders and the dot base 64 because it's a base we want to decode it on base 64 dot decode and we want to decode our secret key.
Okay, so once the secret key is decoded now I need to do just to return keys dot H M AC SHA key for this is one of the algorithms that we mentioned before. And all I need to do is to pass this key bytes. Right? So now we have our get signing key method. And we have also this extract all claims method ready to use.
Now we have extract all claims method ready to use. I will go ahead next and implement another method which will allow me or which can extract a single claim that we pass okay so I will use generosity for this so I will use a public t it I want it to be a generic method and they will call it extract claim and for this claim I need of course the token the key token or string token and then I want to pass a function, the one from Java utils, and this function is of type claims, and t, which is the type that I want to return. I will call it claim resolver, or claims resolver, or claim, call it whatever you want, resolver, and here it's a simple method. I will create a final claims object.
I will call it claims. equals extract all claims from my token okay so first of all i want to extract all the claims and then i want to do return this claim resolver the function that i pass as parameter dot apply and as you can see the apply it will take or it will require a claims t so the claims is the one of the list of all the claims that we have okay so this is the extract all claims all claims method now extracting any claim from my token will be an easy peasy task so i will show you how to do that So once I have everything ready, extracting all the claims and also extracting one single claim, let me show you how we can extract the username out of this token. Okay, so extracting a username is easy peasy. So it will be extract claim, and we need to pass the token and only we need to pass the claims dot get subject. Okay.
so because as i mentioned before the subject is or should be the email or the username of of my user okay so this should be the subject of of the token so that's it this is only all about extracting the username let's now move on and try to implement other methods that we will need within this jwt service class like testing if the token is expired also um extracting the expiration date generating the token and so on so forth let's now implement the method that will help us generate a token so the token as you know is a string so i will create a public string method and i will call it generate token all right so this generate token will take as parameter a map a map of string and object okay and this map of string object will will contain the claims or the extra claims that we want that we want to add okay i will call it claims or like extra claims i think it's better to call it extra claims and also i want to pass my user details. So here user details, and it's the one from the spring framework, I will just call it user or user details. Alright, so this is the method and here this extra claims is the one if I want, for example, I don't know to pass authorities to pass any information that they want to store within my token.
Alright, so to do this, it's easy peasy. It's just written j w t s. dot builder. And then I want to set my claims.
So these are my claims. And those will be the extra claims. Okay, so extra claims. And after passing the claims, I need to set my subject.
So the subject as I mentioned before, it should be my username or user email okay so I will use the object user details dot get username all right so because for us username or the unique part of the user is the email but for spring it's always called username that's why we are using username okay so also we need to set the issued at means the when this claim was created and this information will help us to calculate the expiration date or to check if the token is still valid or not okay so i will use a new date right here and i will pass just the system dot current milliseconds okay so this is the the issue the issue date and i want also to set the expiration date so the expiration date it will be the same a new date and here like it's up to you to set how long this token should be valid okay so also system dot get dot current milliseconds and then for example i want to add let's say 1000 times 60 which is 60 minutes times 24. So my token, for example, will be will be valid for 24 hours plus 1000 milliseconds. OK, and then you can you can decide or you can set any expiration date that suits you. OK, the final step is to sign with like which key that we want to use to sign this token. And the signing key is the get signing key method that we already created before. and then we need to pass also the signature algorithm so signature algorithm and then we want to use the eight the HS256 okay so it's this one so let's select it and then finally call the method compact compact is the one that will generate and return the token so as you can see this is how we can generate a token out of Extra claims and the user details.
All right. So. Now this method will like we don't have a choice but passing claims and user details. But what if I want to pass or I want to use or I want to generate a token without having or without extra claims.
I only I only want to generate a token from the user details itself. So it's easy peasy. I will create another one public. string I will call I'll give it the same name generate token and the generate token it will take it I will pass only user details as a parameter and here I will just return generate token out of null or let's say a new hash map like an empty one and then user details okay so now i have this generate token method that i can use later on okay as a next step let's implement a method that will validate or can validate a token okay so i will create a boolean and i will call it is token valid.
All right. And this token, this method is token valid. We'll take two parameters as input, which is the token itself and the user details.
Why we need the user details? Because we want to validate if this token right here belongs to this user details right here. Okay. So first of all, I need a final string username.
or user email. But within this within the context of this JWT service, let's stick to username. And this one, it will be extract username out of the token, we already have the method for that.
And then then what we want to do is to return if or whether the username that we have right here equals the user details dot get username. All right, so we want to make sure that username we have within the token is the same as the username we have as input. Okay.
And I want to make sure is is token expired, like I need to check that my token is not expired. Okay. And I want to pass my token as parameter.
So this is token expired is a method that we need to create. So let me go ahead and create this token expired and let's implement this token. Okay.
So I want for this is token expired. I want I will create a method. I will call it extract expiration from the token that we have dot before because it's a date. So I want to make sure that it's before.
today's date okay before new date now let's create this extract expiration so this extract expiration should return a date and it has or it passes as a parameter the token itself so it's also easy so it's extract claim from the token and then it's claims dot dot or colon colon get expiration okay so this is how we can extract the expiration date all right so how we have here if the is token expired we have the is token valid we have all the methods that we need so is token valid this one will use it later on so now let's move on and go back finish implementing this authentication filter So here we just finished implementing this JWT validation process or validation service right here. And now we want to go back to this validate JWT process. So within our code, what we did here, we extracted our username. So we have now our username valid. Let's go ahead and perform or finish our validation process.
All right. So here I want to check. if my user email is not null. So I have a user email or I can extract my user email out of my JWT token.
And I want to check something else. I want to check that the user is not authenticated yet because if the user is authenticated, I don't need to perform again all the checks and setting or updating the security context and so on and so forth. So here I want to check if the user is already authenticated. I don't need to do all this process and so on, so forth. All I need to do is pass here and leave it to the dispatcher servlet.
Okay. So to do that or to check if the user is already connected or is already authenticated or not, we have an object called security context holder. And from that, we can get the context. and then we have a method called get authentication and when the authentication is null means that the user is not yet authenticated okay so this means that the user is not connected yet all right so once the user is not connected what we need to do here like when we go back to follow this process we need to perform and to check or get the user from the database.
All right. So once we do this validation process, we want also or we need to check if we have the user within the database. All right.
So to do so, I will create an object called user details, or you can just call it user because our user already extends or implements the user details interface. I will call it user details equals. and here I will use this dot user details service which we don't have yet and here we have a method load by user username okay and the you and my username in this case is the user email all right so here the method called load user by username And in this case, we don't have this user detail service, but let's create one here.
So this user detail service is already an interface within the spring available within the spring framework, and it's from spring framework, security core, and so on, so forth. And I will call it user details service. So this interface, if we check it right here, so here we have some implementation for it. Okay.
But we want our own implementation because we want to fetch our user from our database. All right. So make this one final.
Don't forget this. And let's move on and implement or provide a bean of type user details service. At this level, we need to create a bean of type user details service, or we need to create a class that implements this interface. So and also give it the service or component annotation, so it becomes a managed bean, and spring will be able to inject it. But let's do it in a fancy way.
Within this config package, I will create a class, I will call it application config. So this application config will hold all the application configurations such as beans and so on so forth. All right.
So to make this class a configuration, we need to annotate it with the annotation called configuration. So. at the startup spring will pick up this class and try to implement and inject all the beans that we will declare within this application config all right we also need the required iris constructor in case we want to inject something so what we need to do now is to implement or to create a bin of type user details service and to do so first of all we need to use the annotation bean this to indicate to spring that this method represents a bin and a bin always should be public no private bins and our bin is of type user details service okay so let's call it user details service as easy as that or as simple as that and then we can use a lambda expression so we can use or we can say return a new user details service and we implement the load user by username so we can do like that new user details service like this and automatically you will see here that we have this load user by username method the one that we want to use in here this method right here okay But, but we can make it more simple than that. And we can use a lambda expression. And the lambda expression, it's, it looks like that.
So here we already see that until he is proposing to replace this with a lambda. So we'll just go ahead and click on it. So the lambda is the username. So we provide the username, the one we have as an input within this method right here.
And then we need to provide the implementation okay so in this case what we want to do is to fetch the user or to get the user from the database and to do that we need to inject our user repository okay so let's create a private final user repository let's call it repository or user repository and here Simply what we need to return is userRepository.findByEmail, the method that we created when we just created the user repository. And findByEmail, we need to pass the user name. And since the findByEmail returns an optional of user, here I want to add an or else throw. So in case we don't have or we don't find the the username or the user within our database, we need to return an exception of type, whether entity not found exception, or we can also return the exception username not found exception.
Okay, so I will use the user name, not found exception. And I will just provide here, it should be also lambda. And for example, as a message, we can say user not found.
All right. So here now we have our user details service. So now it's ready to use.
Let's continue implementing our JWT authentication filter. Now we can go back to our filter and finish the implementation. all right so here we have our user details or we have our user and the next step is to validate and check if the token is still valid or not so here i will add if jwt service dot is token valid okay and here i need to pass my jwt and the user details that i just got from the database all right so if the token is valid then what I need to do I need like we have in here we need if the user is valid we need to update the security context and send the request to our dispatcher servlet okay all right so once our token is valid I need to create an object of type username password authentication token so username password authentication token I will call it auth token and this object is needed by by spring and by the security context holder in order to update our security context okay so equals new username and password authentication token and it takes as parameter the user details and then for the next parameter for the authorities I want to pass it as null and then the user details dot get authorities so here because we are we don't have credentials as you remember when we created the user we don't have credentials so that's why I'm passing these credentials as a null value so once I finish creating or finish instantiating this user name authentication token I want also to give it some more details so I will use the auth token dot set details and these details it takes an object so I will pass a new object of type new web authentication detail source authentication details source and here i want to build the details out of our request out of our http request all right now the final step is as we mentioned here the final step is to update the security context holder so to update the security context holder it's security context holder dot get context dot set authentication with our authentication token. All right. And that's it.
Now, let's recap this one. So here, when if we have our user email and the user is not authenticated, we get the user details from the database. And then what we need to do we check if the user is valid or not.
If the user and the token is valid, so we create an object of type username, password, authentication token, we pass user details, credentials and the authorities as parameter, and then we extend or enforce this authentication token with the details of our request. And then we update the authentication token. And don't forget as a last step and always do think about after this if Think about always calling our filter chain dot do filter.
So we need always to pass the hand to the next filters to be executed. Okay. And here we need the request and the response. And that's it about our JWT authentication filter.
It is ready to use. Let's move on and see what we need to implement next. This whole process is now implemented, but we still need to do some extra steps. The extra step we need to do is to tell Spring which configuration that we want to use in order to make all this works.
Okay, so we created the filter, we implemented the user detail service, validation, updating context, and so and so forth. But what we are missing is the binding, we need to bind Because we created a filter but this filter is not yet used so we need to use it and In order to do that we need to create a new configuration class. I will call it security configuration okay, so I will call this class security config or configuration and This is gonna be our security Configuration class and as always to make a configuration class become a configuration we need to add this configuration annotation from spring also because we talk about security right here we need to enable web security let me make it full screen and again we will need the required args constructor so these two annotations they need to they need to be together when we when we work with spring boot 3.0 okay so Next, what I will need to do, because as at the startup or at the application startup, Spring Security will try to look for a bin of type security filter chain.
And this security filter chain is the bin responsible of configuring all the HTTP security of our application. So I will create a bin public. Security Filter Check I will call it security filter chain and within this method or with this bin I will pass a parameter of type HTTP security.
I will call it just HTTP just for a short variable name. Now let's start configuring our HTTP. security so here as you can see it's type it's of type security filter chain and to do that let's first return HTTP dot build and here we need to add also the exception to the method signature because this build might throw an exception alright so now to do the configuration I will start by HTTP dot I will first disable the CSRF verification and we might talk about this in a different video.
So here now once we disable this one and now let's move on or we will implement the configuration the real configuration. So within the security we can choose and decide what are the URLs and the paths that we want to secure but of course within every application we have always a whitelist whitelist means that we have some endpoints that they do not require any authentication or any tokens that which are open for example when we talk about creating an account and logging so in this case to create an account we don't need a jwt token because at that time we will create a user account and we will require or will ask for a token after that also the same when we want to log in we don't need to pass the token as parameter because we don't have one yet so in this case this is when we talk about whitelisting and here is how we can implement whitelisting so after disabling the csrf i want to authorize http requests and after authorizing after using or calling this authorized http request here we can call a request matcher dot request matchers and for this request matchers we can pass a list of strings and a list of patterns this will represent the application or our application patterns we will go back to this later on and for this list i want to permit all i want all the requests in here all the all this list i want to permit all okay and then any request, all the other requests, I want them to be authenticated. So this means I want to whitelist this list and authorize all the requests within this list. But any other request should be authenticated. Okay, now let's talk about and let's see how we can configure our session management.
The session management means what? we said that when we implemented the filter we want a once per request filter means every request should be authenticated this means that we should not store the authentication state or the session state should not be stored so the this the session should be stateless and this will help us ensure that each request should be authenticated okay so now we use the and to add a new configuration. And here, let's add dot session management. And here I want to talk about the session creation policy, how we want to create our session. So as I mentioned, our session, we want it to be stateless session.
Okay, so I will use session creation policy dot stateless. And like this, Spring will create a new session for each request. And then, and here I need to tell Spring which authentication provider that I want to use. The authentication provider, I will explain it in just a few seconds. Okay, so I will just add it.
authentication provider and i will create an object of type authentication provider and then i will go back and create it later on and then after the authentication provider i want now to use the jwt filter that we just created okay so to do that i will use the method add filter before because i want to execute this filter before the filter called username password authentication filter because as you remember when we implemented the JWT authentication filter we check everything and then we set the security context we update the security context holder and after that we will be calling the username password authentication filter okay so here i will use JWT auth filter I will call it like that and I want it before the user name password authentication filter dot class okay now let's let me create this object so I will use the oops not local variable but create a field and this one i want it to be of type jwt authentication filter okay so this is the first one and i need it to be final so it will be automatically injected by spring and the next one is the authentication provider so let's create a field of type authentication provider and let's make it final too All right, so now I have my configuration ready. All I need to do or I need to implement now is this authentication provider. And let's do it right now. Now we need to provide this authentication provider been.
So let's go to our application config. class and let's create a new bin of type authentication provider okay so for this authentication provider let me make this full screen so i won't create a bin and always public and the bin type authentication provider oh authentication provider always from the spring framework package and I will call it authentication provider and let's start implementing this bin right now so this authentication provider is the data access object which is responsible to fetch the user details and also encode password and so and so forth so for this we have for this authentication provider we have many implementations and one of them is the DAO authentication provider. So data access object authentication provider, I will call it auth provider equals new DAO authentication provider.
Okay. So within this authentication provider, we need to, to specify few properties or like not few, but just two of them. And And the first one is the user details service. So we need to tell this authentication provider which user details service to use in order to fetch information about our user, because we might have multiple implementations of the user details. One for example, getting the information from the database, another one based on another on a different profile, fetching the users from from in memory database from LDAP and so on and so forth.
Okay, so for this one, we already have our oops, we already have our user details service right here. So this one is referencing this method. Next, we need to provide a password on encoder.
So which password encoder we are using within our application. So if you have a specific one or if you are using specific one, we need also to precise this one because when we want to try or we want to authenticate a user, we need to know which password encoder in order to be able to decode the password using the correct algorithm. Okay, so auth provider dot set password encoder and here I will create a method.
I will call it password encoder. Okay. And I will create a bean out of it later on. So this is the minimum required information that we need to provide.
And then all I need to do is returning this auth provider right here. Now, I will just go ahead and create this password encoder. So this password encoder is also should be also a bean.
So it will be public and i will give it the bean annotation and for this i just need to return a new bcrypt password encoder and that's it so now i have my authentication provider and also i created the password encoder bean One more step is needed to finish this application config class, which is the authentication manager. And the authentication manager, as the name indicates, is the one responsible to manage the authentication. So the authentication manager have or has a bunch of methods.
And one of them, there is a method that allow us or help us to authenticate a user based or using. just the username and password and for that we need also to create a bean or to provide the bean to be able to use it later on okay so i will create a bean and public authentication manager because this is the bean that i want to to create and i will call it authentication manager and within this bean i want to inject an object of type authentication configuration okay and i will call it config this authentication configuration hold already the information about the authentication manager so i will just return config dot get authentication manager all right so here we are using the default implementation of spring boot and this is more than sufficient for us here don't forget also to add the exception to the method signature so that's it let's move on and now we're done with all the security configuration for our application but we still need to provide at least two endpoints where the user can create an account or also can authenticate and to do so within the base package i will create a package I will call it auth and within this package I will create a new controller authentication controller and this authentication controller will have two endpoints that will allow me to create or register a new account and authenticate an existing user so in order to call this or to make this class a controller we need this annotation rest controller and also I will give it a request mapping and for the request mapping it will be slash API slash v1 slash auth and also I will need the required args constructor okay now within this authentication controller I will create two endpoints one for register and the other one for the authenticate so the first one it will be a post mapping and I will give it a register for the name and here it will be a public response entity and now the type will be authentication response I will create an object later on for that we will call this method register and this register will need a request body and this request body I will create an object called register request, which will hold all the requests or the registration information like first name, last name, email and password. Okay, so I will leave it empty for now.
We will implement it later on. I will do the same I will just copy paste this one and I will create another method. But this one we call it authenticate and it will also return an authentication response but instead of register request we will need an authentication request okay so it's an authentication request yeah that's it so we have our controller ready now let's move on and start implementing things Let's now create our authentication response.
So now just I'm you I will use IntelliJ to create this class authentication response and I will create it within the same package. So this response is a simple class that will have only a string token. So this is the token that would be sent back to the customer or to the user.
And to do that, we will need this data annotation. We'll need the builder and, of course, the all args constructor and the no args constructor. So that's it.
So our authentication response is ready. Let's move on and create the register request. Now let's create this register request class.
So create a class right here and we will create it within the same package. So this register request it will also have few attributes like private string first name, private string last name, and also an email and password. So we will also need the same annotations as we used within this authentication response.
So just go ahead and copy them and put them within this register request. Okay, so now we have also our object register request ready. I will create as a next step the authentication request object.
Finally we need to create this authentication request within the same package so I will just paste the same annotations and here this object will hold only two information which is the string email and string password. okay so that's it our object now ready let's move on and start implementing this author register and authenticate request so for the registration and authentication implementation i will delegate this to a service so within this auth package i will create a new class and i will call it authentication service all right this is the place or the class where i will implement these two methods register and authenticate so here i will just give it the service annotation and of course the required args constructor all right so here we have these two methods i will just move on And here, just make a simple call for this service methods. But first, let's inject it. Okay.
So I will need private final authentication service. I will call it just service right here. And within this authentication service, let me make this full screen. Now I will just.
make the return statements for these two methods all right so here i will return a response entity dot okay and i will call my service dot register and i will pass this request as parameter okay and i will copy paste this and paste it right here and instead of register it will be authenticate So here we don't have yet our register and authenticate method. So let's go ahead and create them. So create method register and this one will return the authentication response. So this is what we want to return.
And now we can also create this authenticate method and the same it should return an authentication response. Alright, so now I will start implementing these methods. So now let's implement this register method and this register will allow us to create a user, save it to the database and return the generated token out of it.
Okay, so for that, because we need or we want to interact with the database and save the user. So the first thing that we need is to inject our repository. Let's call it. repository right here. And then what we need to do, I want to create a user object out of this register request.
So I will create a var user equals user dot builder, and here dot build. So to build this user out of this register request, so I will have the first name, which is request.getFirstName, same for the last name and same for email. So it's email and then the value will be the request.getEmail.
Now for the password, as you remember, we created our Bean of Type Password Encoder. So for this, we need to encode our password before saving it to the database. Okay. So in order to encode the password we need first of all to inject our password encoder service. So I will do that.
Password encoder, password encoder. And this I will use it right here. Password encoder dot encode.
And here I have the get password or the request dot get password that we will receive within the registration request. Okay. So here I will just make a static role always.
So I will use a user role and then we call the build method. All right. So once we build our user object, the next step we need to do is our repository dot save. And we want to save the user that we just created. All right.
And finally. to be to return this authentication response that contains the token i will create a new variable i will call it jwt token equals now i will need my jwt service to generate that token so i will i will inject also the private final jwt service and i will use it to create or to generate the token using this user object right here. So JWT service.generateToken, the one only using user details for the moment, I don't need to set any extra claims.
So I will use this user object to create auto-generated token. And finally, I will return an object of type authenticationResponse.builder.build. and I need to pass dot token or I need to pass the token that I just generated.
Okay, so this is the register method and now everything is implemented. Let's move on and implement this authenticate for the authentication. It's it's an easy peasy.
so you remember we spoke before about the authentication manager bean and we said that this authentic authentication manager bean has a method called authenticate which allow us to authenticate a user based on the username and password so for that i will inject first of all my private final authentication manager bean i will call it authentication manager all right So I will go back here to this authenticate method and to authenticate the user. All I need to do is to call the authentication manager.authenticate. And this authentication manager takes an object of type username password authentication token.
So I will pass a new username password authentication token. And within this, I need to pass the email. So request.getEmail and also the password. Request.getPassword and this authentication manager will do all the job for me.
And in case the user is not, the username or the password are not correct, so an exception will be thrown. Alright, so I'm totally secure when I just call this method. Otherwise, what I need to do. I need to create a user and if the user so if I first of all if I get to this point right here means the user is authenticated so means the username and password are correct if both of them are correct so I will just need to generate a token and send it back okay so I will first of all find try to get the user and find by email and I will use the request dot get email and here or else I will just throw okay I'll just throw any exception like it's not so important at this level but for you you might want to throw the correct exception and you need to catch it handle the exceptions and so on so forth alright so now I will just go ahead and copy this code because it would be the same and put it right here So once I get the user, I will generate a token using this user object and then return this authentication response. So now we have this authenticate method and the register method ready to use.
Let's move on and see what is the next step. Now we have our authentication controller ready to use but there is one extra step that we need to do. Do you remember when we first implemented the security configuration and we spoke about this whitelist right here?
So what we need to provide now within this request matchers that we want to permit all, we need to provide or authorize all the URLs or all the methods that we have. within this authentication controller. So go ahead, copy the request mapping that you created.
And for example, here, I want to authorize all the methods that I have within this authentication controller. Why? Because based on my design, everything that I have in here, only authentication related methods.
So I don't have any business logic methods or endpoints within this authentication controller so that's why I'm allowing I'm allowing all the methods within this controller so that's it now let's create a demo controller for that I will create a new controller within a new package so right click here new class and I will call the package demo. And I will call it demo controller. So this demo controller will be also secured. So I want this endpoint to be secured, I will copy this, these annotations right here, paste it here. And so this one will be demo.
And let's call it demo controller. And now i will create just a get mapping a simple method that public that will return a simple string okay response entity of type string say hello for example and then i will just return a response entity dot ok and with a body hello from secured Hello from Secure Endpoint and that's it. Now let's go ahead start our application and test these changes.
Let's start the application and make sure that all the code that we wrote together is working fine. So go ahead click on start and let's see what we will have. in the console so let's make sure that everything is fine so as you can see here from the logs we no longer have this auto generated password by spring security and we have here that you are creating the sequence and we have the table user gets created and the application is running correctly okay so now let's start our postman and test this endpoint so i have my postman started right now so i will use this endpoint within a get request so the endpoint is localhost and my port is 8080 slash api slash v1 slash demo controller is the same one that i have right here within my code it's demo controller and now i will click on send we see that we have no authorization we have nothing in here So I will just go ahead and click on send and normally like the expected behavior is this endpoint should be secured. Okay, so when I click on send, we exactly can see that we have a 403 forbidden means that we are not allowed to access this endpoint.
Okay, next we have our two endpoints, the authenticate and the register. So let's first start with this register endpoint. or let's before that let's start with authenticate and for the authenticate now we know that we have no user within our database we can also double check that so if i open let me close the other tabs so here i don't have any user registered within within my database okay but now if i try to connect to or to authenticate a non-existing user i also expect to have a 403 as a response and this is what we see right here so it's 403 forbidden and the user is not allowed to access this endpoint and this why because we have here within our schema so we try to check and validate everything even if the endpoint uh even if the endpoint is secured so we we get into this authentication filter we validate everything But once we get to the user details, we don't have the user in the database.
So in that case, we will send back a 403 to our customer. OK, so now let's create a new user. So I will register a new user. So I give it Alibu as a first name, Alibu last name and Alibu at mail.com and 1234 as a password.
So now when I click the send button, I should get. generated token or a JWT token as a response so this is what we see right here so I will just copy this token and I want to decode it and let's see what we have within this token so let's go back to the JWT.io website and paste the generated token in here so we see that we have the algorithm here which is the HS2 five six the one we use to generate this token and we have our payload so we set already the subject to the to the user email and we have the issued at so the creation date and as you can see in here it was created december 29 and 14 14 and this one will expire at in 24 hours okay so uh this is our generated token let's go back and test the authentication right now so we see that the register is working but let's ensure that within this same username and password we are also able to get a token or to generate a token so this is the same email and the password that we have and if i click on send i should get the token but let's first try with a wrong password so when i click on send so here we have our 403 and here it's because of this process so we have the token and then we start the validation process so we extract the username and password and then we are calling the user details service to try to fetch the user from the database and the user we got it because the user already exists but when we move to the security filter chain and to use when we move to security context holder we will try also to use the authentication manager to authenticate that user using the password and the user mail that were provided within the request but this password is wrong so that's why we are also throwing a 403 as a response okay so now let's test with a correct password so if i click on send i see that i have my jwt token i will copy this one And then I will go back to this get method. I will click again and make sure that it's always 403 and how we can authorize this request right now.
So within the authorization here within the type, click and choose bearer token. All right. So remove or delete if you have something in here and paste the token that you just copied. OK, now click on send.
and we see that we have the message hello from secured endpoint and we have this 200 okay which which is compatible with all this process so we have the filter we validate everything we check the token user details and then we pass everything to security context holder we updated and then our request is sent to the dispatcher servlet hit the controller and then we get our response pack So I hope this was clear. If you have any questions don't hesitate to drop a comment and especially don't forget to follow me to learn more and more about Spring Boot. Okey dokey. Congratulations.
Now you know how to implement JWT using Spring Boot 3, which is the latest version of Spring Boot and Spring Security as well. If you enjoyed this crash course, literally just take one second and smash the like button. Also if you haven't subscribed to Aliboot channel, go ahead and subscribe. It's got awesome content around Spring Boot, Java and Angular. It was a pleasure.
This is all for now. and i'll catch you on the next one assalamualaikum