Master Spring Security JWT in 1 Hour

TheCodeAlchemist · Intermediate ·🔧 Backend Engineering ·10mo ago

Key Takeaways

This video demonstrates how to implement Spring Security JWT in a Spring Boot application, covering user registration, authentication, and authorization using JWT tokens.

Full Transcript

Hey everyone, welcome back. So in the last video we covered the fundamentals of JWT. What JWT is, what is the general authentication flow with JWT. Now in this video we will do the hands-on we will develop a backend service which will expose a protected endpoint and then using Postman as a client we will access that endpoint using JWT token. So let's get started. [Music] So as we discussed the authentication flow in the last video on JWT fundamentals, we remember that we need a user store. Why we need a user store? Because we haven't covered anything about OOTH which is generally used with JWT. So we need a user store to store the user so that we can implement the authentication flow. We can later compare the username and password. Now this authentication is required because after this authentication only the server will generate a JWT token that the client can send in subsequent requests. So in this case in this hands-on session what we will do we will have a user store. We will use Postgress as the database and we will also implement a user registration flow. In this user registration flow, the user would register itself and the details will be stored in the database and then we will develop the authentication flow in which the user will provide the username and password and we will write the logic to authenticate the user based on the username and password and we will be able to do so because we will have the data in the user store which is the postcrist database. So after this authentication the server will generate a JWT token that will be sent back to the client and then we will implement the protected endpoint flow where we will implement the validation of JWT. How can we validate the JWT token provided by the client and if the JWT token is valid then we will let the user access the protected endpoint. So let's start with the user store implementation which is the user registration flow. So this part we have done multiple times in this playlist the user registration part. So I'm not going to cover this part from scratch to save some time. So to save some time I have already implemented the user registration flow and I will give you a complete walk through so that you can do on your own and then we will start implementing the authentication flow and JWT part together. So let's start from the pom.xml. Let's understand the dependencies that we have at this moment. Now we need starter data JPA because we need to store the user data in the Postgress database. We need starter security. We need starter web because this is going to be a web application. Then we need the postcrist database driver in case you choose another database you need to update the driver. Then we have Lombok to generate getters and setters and then the test dependencies. As you can see we do not have any dependency related to JWT yet. We will add them as we go. All right. So you can create this simple project by going to the spring initializer. Just add the required dependencies that I have highlighted. download the project and start implementing the user registration part. The second important thing is application.ml file. You can ignore the secret key for now. This is going to be used in the JWT flow and I will cover it later. But if you just focus on other properties, this is the name of the application. This is the database details. So that is the database that we are going to use. And if I go to Postgress, you can see this is the database that I have created. Now this database does not have any tables as of now. This is empty. This application will create the missing tables on server startup because we have provided this property hibernate DDL auto to update and then we have the database dialect for Postgress. So that is the minimal configuration that we need in this spring boot application. So let's now go to the registration part. So here we have the registration controller which is exposing an endpoint API o register. So the client would hit this endpoint to register itself into the system and this endpoint is accepting a user DTO and if we check the user DTO it has three details username, email, password and role. Now in this demo we will also implement the rback which is the role based access control. So in this case the user would have a role field as well. All right. Now this data will be stored in the database. So let's go back to the controller. Once we have the data from the request, we are calling the user service to register the user. And if the service returns true, then that means the user has been created successfully. If not, we will return a response which is the error response. Let's now go to the user service. So in this user service, we have the register user method and here we are creating a new user. Now this user is the JPA entity. So let me open this up and you can see this is the user entity which is mapped to users table and it has several fields like ID which is the primary key, username, email, password and the role and you can see we are storing the string values of the role because role here is an enum. So let's check this out and you can see we have only three roles admin, user and guest. So when we store the user via user JPA entity, we will also store the role of the user which could be admin, user or guest. All right, going back to the user service. So here we are creating the user basically using the JP entity. So we are setting the username which is coming from the incoming request. Then we are setting the password, email and role. For the password, you can see we are using password encoded to hash the password. This part we have already covered in this playlist. And once we have the user JPA entity enriched, we are using the user repository to save the user. Now if I check out the user repository, you can see this is simple spring data JPA repository extending the JPA repository and it has a method find by username which is a custom method. I will cover this as we go. So this will save the user data in the database and that is going to be the users table which is mapped to this JP entity. So as you can see this service is also implementing the user detail service and we have covered this interface already in this playlist in the HTTP basic demo. So this interface is a way for spring security to know how to load the user. Spring needs to know how to load the user and by using this interface we provide the implementation of load user by username. So what spring security does it simply calls this method and how we implement this method is up to us. In the end, it returns a user details which is the loaded user itself and that's how spring security loads the user in abstraction. All right. So that is why we are implementing this interface because we will we need to authenticate the user and to authenticate the user we need to compare the username and password to match the username and password we need the user data that is why we are using user detail service. So in the authentication flow what will happen the framework will use this method to load the user and then we will write the username and password matching part before generating the JWT token. So that is why this implementation is required. So because we are implementing this interface we need to provide the implementation of load user by username which is accepting the username coming from the incoming request. Then to find the username from the database because in this case the user store is postcrist database. So that is why we are fetching the data from the database. Suppose in other scenario we could have an external API that will return the user. So instead of fetching the data from the database here we will write the logic to fetch the user details from the external API. All right. So here because we have the data in the post grao we need to access the user repository and we need to find the user by name not by ID. That is why we have added this custom method find by username. Then once we have the user data back from the database, we are creating something called authenticated user. And this authenticated user is nothing but the implementation of user details. All right. Now user details has several methods like get authorities, get password, get username and this is the username and password detail coming from the entity that we have just loaded from the database. Then the next important thing in this entity is the authorities section because we are also using rules in this scenario. The next important thing to understand here is the authorities. Now in this case because the user can have the role. So we need to return the correct authority so that the role can be compared. Now this part we have already covered in the roles and permissions video. So please check out that video to understand the core principles of roles and permissions in spring security. All right. In a nutshell, the authorities or the roles and permissions are called authorities in spring security language and these are represented by granted authority. Then we have the implementation of granted authority as simple granted authority. So from this method we will return the list of all the simple granted authorities. Basically all the roles or permissions this user would have. Now in this demo because each user would have a single role that is why we are returning a single simple granted authority object. Now the value of this object will be the role of the user with a prefix role underscore. Now in that video that I'm referring you will find that any string can be used as a role as well as a permission. So how do you distinguish between the role and the permission? So if you prefix rule underscore with any string value that particular string value will be treated as a role not as a permission. So because we are going to implement the rule part that is why we are prefixing role underscore. All right. So from this user we what we are returning is the username the password and the role of the user as simple granted authority. Then we'll go back to the last part which is the security config. And here you can see we are creating the bean of password encoder that we are using in the user service to hash the password. All right. And then we are configuring the filter chain. This is not complete yet but we will complete this as we go with the remaining bits. For now you can see that we have disabled the CSRF as always because this is going to be a purely backend application. Then in this section we are matching the endpoints and we are permitting API o register endpoint. So you can see if the request matches this particular pattern then we need to permit all otherwise any other request will be authenticated. Now one thing you should notice here is that this does not have any information related to HTTP basic as we have been doing in the previous videos. Although we are implementing user detail service and storing the data in the postgress but we are not going to use HTTP basic authentication mechanism in this case. We will use JWT and we will cover the details. How do we match the username and password? How do we authenticate the user without using HTTP basic. All right. So now that we have covered the basic project setup, the user registration part, we will now move on to the authentication part where we will authenticate the user and we will also generate a JWT token. So before we start the implementation, we need to understand some key things about the implementation. This is the GitHub page of JWT for Java and you can find almost all things related to implementation on this readme page. So I suggest you go through this readme page and check out the details how to implement JWT. Let's go through this together. So here you can see many sections like installation where we will find the required dependencies. Then we see section creating a JWT that will tell you how to create a JWT token. Similarly we have section for reading a JWT. So once you have the JWT token, how do you pass the JWT token then there are details how to sign the JWT, how to encrypt the JWT token and all these things. So we can start with installation and here we can see the required dependencies that we need in order to implement the JWT. So we'll have to add these dependencies to our form.xml. Then in the quick start section here we can see a simple flow of how to create a JWT token. So we need to first use the builder and then we can add the claims like in this case we are adding the subject then you sign the token and then you create the token and you can see to sign the token we need a key and that is where we are creating the secret key and this is the same reason why we added a secret key in the application.properties file and you can use the same example this line of code to generate a secret key. You can pre-generate the key by calling this code and you can just copy the secret key and add it to somewhere. let's say application.properties or a vault. All right. So once you have the secret key, you can use the key to sign the token. And in this example, this represents your JWT token which is signed JWT token. And in the same way, we will create the JWT token from the service when we return a token back to the client. Now in the subsequent requests, when the client sends the token, how do we pass the token? And we can see the example over here that we use the parser, then we verify the token with the same key. That is why we need to store the key to a common place that can be used while generating as well as parsing the token. So once we verify the token, we get something called signed claims because the token was signed and from the signed claims we get the payload and from the payload we can get all the claims which were added to the token like subject in this case or if you added some custom claims we can extract that information as well from the payload and we can see more details under respective sections like creating a JWT. So things that we have covered we need to use the builder. Then we can add headers if we want to. Then additionally we can add other things by using the builder methods. Then we can either sign the token or encrypt the token. So there are two methods to sign the token with a key. We use the method signed with. To encrypt the token with an encryption key we use the method encrypt with and then we call the compact method that produces the result as a compact JWT string. And here we can see the sample that we are using a builder. Then this is adding some optional headers. Then this is the subject. And then you can also add custom content to the payload. Here is an example. Then you can sign the token with a signing key. And if you want to encrypt it then you can call encrypt with method with a encryption key. You in this case you also need to provide the encryption algorithm. So that is how we generate the JWT token. And similarly you can find other details like how to add custom headers to JWT. This is all here in the documentation. Let's move on to understand how do we parse the JWT token. All right. So this is the section where it tells you how to read the JWT token. So to read a JWT token, we need a parser which is a builder method. Once you get the parser, we need to verify the token. So if the token was signed, then we verify the token with the key. If the token was encrypted, then we need to decrypt the token with the key. Then we call the build method that will generate a JWT parser. Here you can see. And then we need to call the parse methods to parse the token. And here we can see the example. We can simply call the parse method or we can call parse signed claims. Let's say if the token is signed, if the token is encrypted, then we will call parse encrypted claims. So you can find the example here and we will also see the example in the project as well. So you can go through all these details related to keys. So you can find more information here like how to verify the token, how do you encrypt the token all these things are given over here and similarly uh you can find the details related to the signed token and encrypted token. So here you can see sign JWTs and these are the algorithms which can be used to sign a token. All right and similarly you will find the information related to encryption as well. So this is telling you how to create a JWS. JWS is nothing but a signed JWT token. Assigned JWT token is called JWS. And similarly, encrypted JWT token is called JWE which is encrypted JWT token. And we can find the same on the documentation somewhere over here. Encrypted JWTs. Okay, this is JWE encryption algorithms. So there is a lot of info on this readme page and you can go through this in your own time. But we got the gist how to create the token, how to pass the token and we will use this information in the project. So let's move on with the hands-on. Okay. Okay. So the first thing that we need to do is we need to add these dependencies to the project. So let's do that. We'll go to the pom.xml and we'll add the required dependencies. We can add anywhere in the project. And then we need to reload the dependencies. So once we add the dependencies, the next step is to implement the authentication flow. So if you go back to the diagram, we know in the authentication flow, the client would register itself. All right. So the first thing is to register the user that we have already done. So the user is already in the database although we haven't run the program yet but we already covered the implementation that part is already implemented. So in the authentication phase the client would enter the username and password then the backend service would authenticate the user and if the user is present in the system if the username and password is matching then the server would generate a JWT token and it will return the JWT token. So we need to implement this authentication flow. So let's do that. To intercept the authentication request, we will add a new controller. And that will be the authentication controller. And this authentication controller would be a rest controller. And in this rest controller, we will add a new method login. which will be a post mapping. It will be a post call and let's give it an endpoint API or login. All right. Now in the request we will get the data from the request using request body annotation and we will also create a record in this case to capture the information. So that will be the login request like this and in the same way we can generate the response because in the response we need to return the token. So we will also create a response DTO in this case which will be login response. Okay. So let's create the missing details. This will be a record login request and this record would have three fields username sorry two fields username and password like this. And similarly we need to add the other detail which is login response. And in the login response we would have a single field which is the token like this. So in this login endpoint first we need to authenticate the user then we need to generate the token and then we need to return the token. All right. So how do we authenticate the user? So to authenticate the user because we will not be using HTTP basic. So we need something called authentication manager. So for now what we will do we will simply autowire the authentication manager and later we will also configure the authentication manager. So suppose we already have the authentication manager. Then autowiring the authentication manager is as simple as just using the auto annotation like this. So once we have the authentication manager, how do we trigger the actual authentication? We use the object of this authentication manager and we call the method authenticate. So if we check out the authenticate method, we can see that this is an interface that is why it has a single method because this is a functional interface and the authenticate method accepts an object a type of authentication. So how do we pass the authentication object? Now in this demo because we are going to use the username and password but not the HTTP basic method. So we will pass an object of username password authentication token this one and it accepts two parameters and sometimes three depending on the constructor that we use. You can see the first one is principle then the second one is credential and for the second constructor the third parameter is authorities. Now we are going to use the first one which will take the principle and the credential. So what is going to be the principle in this case? Principle is nothing but the username and we get the username from the incoming request using this DTO and the credential would be the password. All right. Now the authenticate method would return an object of authentication. this one. All right. So, how would this trigger the authentication? Since we are passing this authentication token which is username and password authentication token to the authentication manager. So, authentication manager would check from the list of available authentication providers that which authentication provider can handle this type of authentication. Now we have already covered the concepts of authentication manager and authentication provider in the first video where we covered the overall architecture of spring security framework. So if you don't understand the authentication manager and authentication provider, I suggest you check out that video first. So in this case, authentication manager would check the list of authentication providers to see if there is an authentication provider available that can authenticate the user depending on this authentication token by username and password. Now what happens by default there is an authentication provider which is made available to us by the spring security framework and that is DAO authentication provider. DAO authentication provider internally uses user detail service and if you remember we are already implementing user detail service. So when we pass this username and password authentication token, it will trigger the authentication provider which is DAO authentication provider and DAO authentication provider internally will call the user detail service. this method load user by username that is how this will fetch the user by the username and it will also match the password. All right. So as a result we will have the object of authentication which basically represents the authenticated entity in this case. All right. So once the authentication part is done how do we generate the token? Because if we go back to the diagram we see once the authentication is done user authentication part we need to create the JWT token. So how do we generate the JWT token? To generate the JWT token, we will write some code that can use this authenticated principle and can generate the JWT token. So to generate the token, we will add a JWT service. Let me add the placeholder. All right. And then we will use this JWD service which will have a method generate token. And to this generate token we will pass the principle in this case. How do we get the principle out of this authentication object? Well, there is a method get principle. And the principle if you check the data type of this principle, this is an object. We need to convert it to a usable entity. And in this case that entity is authenticated user. Why authenticated user? Because if you notice this is the class that we created which is implementing user details. What is this user details? If we go to the user service user details is the object that will be returned by this load user by username. Okay. And which is a concrete type of authenticated user. That is why this is the principle that we will return. So generate token will create a JWT token which will be a string. So we will save it to a string value token and in the end we will return the response. And in this case this will be an object of login response. And this login response has a single field which is token. So that completes the authentication controller the o controller. All right. And we need to add the service now. So let's add the service. We will add the service to the service package. We will also annotate it with the service annotation and then in this service class we will add the method generate token. All right. So once we pass the request to JWT service we know we have to create a new JWT token. How do we do that? Well, we have already seen the example on the GitHub page of JWT Java and we will use the same same syntax. Basically we will use the builder. Then we will add the principle some claims and then we will generate the JWT token. So let's do that. So the class that we will use is JWTS dot builder compact. But we need to add some details. So the first one is subject. Who is the subject for this token? The subject is the principal. All right. And this is the authenticated user. So what we will do? We will add the subject. Subject is the username who is trying to login. What else can we add to this JWT? Well, we know we can also add some claims to the JWT. And we can also add custom claims as we covered in the last video. So, there are two methods. The first one is claim where we can add a single claim. This is the key. This is the value. And we can add multiple claims if we have a map using claims. So, in this case, I will add a single custom claim. Let's do that. The key would be anything that I want. So I want to add the roles that this user have because when we are creating the user, we are also storing the role of that user whether it is admin, guest or user. All right. So I can add the role of the user while generating the JWT token. How do I get the roles of the user? Well, if you go back to the user service, then here you can see I'm fetching the data from the database. All right. And this is the user JPA entity. And in the user JPA entity we have the role property. So when we fetch the data from the database from the users table we will have the role in the JPA entity. Then when we are creating the authenticated user you can see that it has a method get authorities in which we are using this role. So when we call this method we will get the role string for that user and that's what we will use here. So I would say principle dot get authorities and this is the method coming from authenticated user. Okay. So this is a single list a list of single value. So get authorities dot stream dot map granted authority get authority and then we can collect the list like this. Okay. So what we are doing because in this case the user has a single role but in general a user can have multiple roles. So in that case the user would have multiple authorities. So we are simply because this is a list of simple granted authority. So we are getting the individual authority. Okay. We are mapping the individual authority to get the name and then we are collecting them as a list. So that's how we can add custom claims. And here we are adding the roles as custom claims. All right. What else can we add? Well, we can add something like issued at when the token is issued which could be the current time like this. We can also add the expiry time of the token that we can do using expiration builder method. So in this method we can pass an expiration time after which the token will be expired. So let's say that we want to have an expiration time of 15 minutes. So how do we do that? Well, we'll create a new date time. We we actually have to provide the actual time maybe in milliseconds or seconds whatever you want. So I will do something like this system dot current time millies. Okay, this is the current time. Then something like this. So that is going to be the expiration time for this JWT token. The last step is to sign the token and we know we do this by using sign with. And you can see it has two methods by passing it a key or by passing it the key and the digest algorithm. So we will use this method. We will pass it a key. So how do we sign the token? Where do we get the key from? So if you remember in the application.properties file, we had a property secret key. And this is the key that I pre-generated. And we saw in the readme section of GitHub page that there is a method that you can use to pre-generate the key. All right. So just pre-generate the key and store it somewhere and use it while signing the token. So I will use this particular key. So we need to read this property in the service class. So let's do that. We'll go back to the JWT service and here in this class I will read the property. Okay. So that property will be injected to this class and we will have the access to secret key. And then what we do we pass this key. So we will say something like keys dot hmac sh key for then there is some syntax that we need to use. I will show you the right place in the documentation on the github page where you can find all these details. So decoders dot base 64 do decode and secret key. So that will generate a JWT token. What we are doing? Let's recap. We are adding the subject which is the username. Then we are adding a custom claim which is the role of the user issued at when the token is issued. Then we are setting the expiration time of 15 minutes. Then we are signing the token. Now this code is directly coming from the GitHub page. I will show you in a second. The only thing is you need to pre-generate the key. All right. So this will create the JWT token which will be returned to the authentication controller and the response would be sent back to the client. So the client would have a JWT token. So that completes this part where the user would provide the username and password. The system will authenticate the user and then it will create a JWT token. So the client would have the JWT token. Next we will implement this part second part where we will have a protected controller a protected resource that the client needs to use but it will have to pass the bearer token and we will write some code to pass the JWT token the past JWT token. We will see if that token is valid not expired and if the token is valid we will allow the client to access the resource otherwise we will reject the request. Let's move on. All right. For the second step which is to access the secure endpoint I have already implemented a protected controller which is exposing an endpoint API secured. Now the idea is that any user who wants to access anything with API secured it has to be authenticated. All right. So there are two endpoints. one default endpoint which is the get mapping which says basically hi user you are allowed the same method but there is another method which is only available for admin so there is this endpoint which is API secured/admin and the method says hi admin you are allowed and then you additionally see this annotation which is pre-authorize which says has role user has role admin so this is one of the ways to basically apply the role checks are back so what would happen let's say if the client is allowed to access this endpoint then there is additional check to check the role of the user whether the user has been authorized or not. The user is authenticated that is one thing. It means the user can login into the system but authorization decides whether you can access a resource or not depending on the permissions that you have been given. So that is why we are using at the rate pre-authorize. This method this annotation is used to apply the role checks. And here you can see the code says has role. So that means spring security at runtime will check the user the authenticated principle who's trying to access this endpoint does it have the role user if yes then this method access will be allowed and the user would see this response on the console whether it is on the browser or on the postman if not then it will be a rejected error. In the same way when the user is trying to access this endpoint the code or the framework would check whether the user has this role which is admin or not. If the user has this role admin then the access will be allowed otherwise the access will be rejected. So that is the protected controller. All right. Now the second step is when the user passes the JWT token using bearer token. How do we validate the token? Because the token validation would decide whether the user can access this controller or these endpoints or not. All right. So how do we validate the token? How do we intercept the request? Well, to intercept the incoming request and to parse and validate the JWT token, we will add a new filter in this case. So, let me add a new file which will be JWT filter and this will be in the filter package. Now, this filter would extend once per request filter. So as the name suggests this filter will be executed once per request. We need to add the methods missing method which is do internal and in this method we have access to the request the response and the filter chain because as we covered in the first video in the spring security architecture overview there are a series of filters which are executed when a request comes and similarly when the response goes back to the client all those filters are executed again. So there is a chain of filters which the spring security framework or spring web will execute. All right. And in this chain we are adding a new filter JWT filter which is once per request filter. The framework would internally call do filter internal this method. All right. And then it will execute the code that we will write here. The first step is we know the token would be passed in the header. All right. As the bearer token. So the first thing is we will read the value from the header. And how do we read the header? We have the access to the request object. So we can say request.get header. Authorization is the name of the header in which the bearer token would be passed. All right. So we will see whether the header is valid or not. So how do we check that? We say if the header is null or header does not starts with bearer that means it's a different header. Then we do not trigger the JWT authentication part. All right. In that case what we will do? We will simply delegate the responsibilities to the filter chain and that can execute the next filter in the chain. and we return from this filter. All right. So if the filter is null or there is another filter which does not starts with bearer token because we are only interested in the bearer token value then our job is done. We delegate the control to filter chain by calling do filter method which will take care of the remaining filters in the chain. But if the header is present and this has the value that starts with bearer then we know that there is a bearer token and we need to fetch the JWT and validate the JWT token. So we move forward. What we will do now? We will fetch the token from this header value. So that is going to be substring 7. Why 7? Because that is the length of this string. All right. bearer and we know in the header the value would be bearer and then the JWT token like this. So that is why we are simply extracting this particular part this token value from this string that is why the substring call. So once we have the token from the header value we need to pass this token because we need to get the user details its roles and all those things that we added while creating the token. So how do we get the username from this token? Let's do that. So I will say username and now we will use the same JWT service where we were creating the JWT token because we need to write some code to pass the JWT token. Extract user and then we need to pass the token value that we got from the header. Let's autoware the JWT service. Okay, so we don't have this method yet. Let's create the method now. Now, how do we read the JWT token? Again, we will use the same samples that we got on the GitHub page of JWT Java. So, you can refer to that. So we need to use JWTS dot we call the method parser. The first step is we need to verify the token. So to verify the token we need to use the same key. How do we get the key? We already know we have the key here already. So we need to use this code again and that will verify the token. Then we call the method build and then we need to passse the signed claims. All right because this token is signed. So the claims that we get are also signed. So we use this method par signed claims and then we pass the token to it. Then we call get payload which is the basically the payload from the token and from this payload we can get the subject. So if you notice when we created the token we called the method subject and in which we pass the username that is why from the payload while reading the token when we call the method get subject we will get the username back. All right so that will return the user back to the JWT filter. Once we have the username extracted from the token we will now validate the user. So how do we validate the user? Well we will check if we have a matching user in the database. How do we do that? We already have the method load user by username in the user service and we can use that method to check if the user exists in the database with the same name. So let me auto add the user service as well like this and we will say user details user from DB user service.load user by username and we will pass this username that we got from the token. So if we found a valid object from the database then that means the user is valid because we found a matching user in the database. Okay. So what is the next step? The next step is we identified the user. The next step is to validate the token whether the token is valid or not. So to do that we will write some more logic here. We will say if JWT service this is the service that we created is token valid and we pass it the token and additionally we can pass the user that we got from the database because it would have other details like roles and all those things. Okay. So this method does not exist yet. So let's create this method is token valid. Now in this method we can write any logic that is required to validate the token. Now in this case in this demo we have already identified the user. We matched the user. We found a matching user in the database. So we can omit that part. We don't need to validate the username anymore. But what we can do we can simply check if the token is expired or not because if you remember we added something like issue date and an expiration time. So we can check whether the token has expired or not. Is it valid? So that's what we will do in this example. So let's fetch the expiration time from the token. How do we do that? Well, the same thing. JWTS dot parser dot verify with and we can probably also move this code to a common method so that we don't have to repeat it again. But that should be fine for now. So verify with then we call the build method and as before we call the par sign claims we pass it the token then we call get payload and from the payload we call get expiration. So that will return the expiry that was configured and that is available in the token. Then we can check something like this. return expiry dot before new date. So that is actually comparing the expiry time from the token to the current time. If the expiry has expired then that means the token is not valid anymore. All right. So here we are just checking the expiry of the token in this method is token valid. So this will return whether the token is valid or not. Let's go back to the filter. So if the token is valid, what do we need to do then? Well, that means we found the matching user and the token is also valid. So in that case, we create an authenticated principle. All right. To represent that this identity has been authenticated. How do we do that? We know it already. We will use the same token that we used earlier. Username, password, authentication token. New username, password, and authentication token. And what do we need to pass it here? Well, in this case, first we need to pass the principle and we know this is the user from the database like this. The second thing is credential in this case because there are no credentials. We are using the JWT token, not the username and password authentication. So we will pass it null. The third thing is granted authorities. Now where do we get the rules? Well, if you remember when we created the JWT token, let's go back to the JWT service. When we created the JWT token, we also added a custom claim roles. So we will fetch the roles again from the JWT token and we will pass it here to this authentication token so that the roles can be checked as well. All right. So let's do that. JWT service dot extract roles pass it the token. This will return a list of roles because a user can have multiple roles. All right. And then the similar logic that we wrote here. So let me copy it from here and we'll paste it here like this. And once we have the authentication token, we need to do one more thing. We need to add this authentication to the security context holder. And once everything is done, we will again do the same thing filter chain dot do filter request and response. So what we are doing here is uh why this call? Because as you remember from the first video that the security context holder holds basically it is a kind of a thread local object for each request which holds the authenticated principle. All right. So when we use for example HTTP basic that part is already handled by the framework. It creates the authenticated principle after the authentication and it updates that data in the security context holder. But because we are doing this thing manually using JWT token verification once the user or the once the principle is authenticated we need to set the security context holder so that it is available to the spring security framework. All right that is why we need to do this thing. The last step is to add this method basically to extract the rules from the JWT token. So let's do that. Now in this case we will do the same thing. So I can copy this part here and this must be list of string. All right. So I will do something like this. pass signed claims then I will say get payload and in this case because we added it as a custom claim which internally is a map we will call the method get and we will pass it a key what was the key the key was rules and what is the value we want it to be a list like this so that will return a list of roles extracted from the JWT token which were set earlier while creating the JWT token this is the roles key that we passing here. All right, back to the JWT filter. Most of the things are done here. What we are doing, we are reading the header. Then we are fetching the token value from the header. We are extracting the user from the token. Then we are matching validating whether we have the user in the system by the same username by calling the user service load user by username. If we found the data in the database, then we are checking if the token is valid. And if the token is also valid, then we are creating the authentication token. basically the identity of the authenticated principle updating the security context holder and the rules as well. There is some problem here. Let me correct it. And this must be a mistake because now we need to convert it back from the string value to simple granted authority object. So that must be simple granted authority new like this. Okay. Now if you notice we are not handling any error in this case although we should. So for example, if you don't find a matching user in the database, you should reject the request. All right. So these things we can do here in the JWT filter. Okay, we are mostly done. We are nearly done. The only thing remaining is some configuration changes in the security config to make it work. So let's do that. Now here in the authorization request section what we were saying that any request which is matching o which means register should be allowed but any other request must be authenticated. We need to do one more thing. We need to enable the stateless session management because this is JWT and we want it to be stateless so that each request has no state of the previous request. It does not know anything about the token that was sent earlier. How do we enable that? Session dot session creation policy. And here you can say we can pass stateless like this. And the second thing is we need to add the JWT filter. Although we created the JWT filter but we have to tell spring security how to execute it, where to execute it because there is a chain of filters. So that's what we will configure in the security config. So there is a method called add filter and you can say before add after. So there are locations that we can define while adding a new filter. So we are going to use add filter before. What is the filter? Well, we have JWT filter and before username and password authentication filter. So there is an internal filter already available username password authentication filter but we want our JWT filter to be invoked before this filter. Now how do we get this JWT filter? Well that is simple that is simply a bean. So let me do that. Bean public JWT filter. And here we will create a new object JWT filter. That's it. So that will create the bean for JWT filter and add it before username and password authentication filter. There is one more thing missing. If you go back to the O controller, we are autoiring the authentication manager but we are not configuring it. So that is one more thing that we need to do. So I will create a new bean method and here we will return the authentication manager. How do we create the authentication manager? Well, there is this syntax that we need to use. We need to use authentication configuration like this. Now this is an object that will be created and injected by the spring security. All we need to do is we need to use it. So we will say configuration dot get authentication manager and that's it. Okay. So we are nearly done now. Let's go back and simply check all the details. So we have the security config. We have the O controller which will authenticate the user and generate the JWT token. Then we have the protected controller which will allow the access only if the user is valid. The JWT token is valid and it has the right permission. Then we have the registration controller which will help the user to register itself. Then we have the DTOS the entities JWT filter that we created. Okay, in which we are validating the token user repository, authenticated user, JWT service which is kind of a utility uh service for JWT and the user service. So now let me run the application and let's see how it goes. So we got an exception which says could not resolve placeholder secret key. Well, if you go to the application file, we have the secret key available. Okay, so we missed this one. So it must be JWT dot secret hyphen key. So let's go back to the JWT service. And here it is. It must be JWT dot the full path. Let's restart. So the service is up and if we check the database, let me refresh. So we can see we have the table users. And if we select the user table, then it must be empty because we haven't created any user yet. And we can see the table is empty. All right. So the first step is done. We have the service up and running. Now the first flow would be to register the user. Let's do that. So we will use Postman to do that. And uh let me go to the JWT token. The first step is to register the user. So here we have the endpoint of register and in the body we have four parameters. But for this demo we added only two in the login request. But we also need the role. So let me add one more like this and I will restart the application. So the service is up and before we move on let me quickly check one more configuration which is the enable method security. This is required because in the protected controller we are using this annotation pre-authorize to check the role. So we need to use this annotation to enable the method security using annotations. So that is all done. Let's go back to the postman and we will use username password. We'll remove the third parameter which is the email because we have three fields username, password and role. So let's do that. Let's first register the user and we can see that the user created successfully. Let's go back to the database and uh let's see if we got the user. So you can see the email is null because I did the same thing in the JPA entity. I added the email field but that is fine. The important thing is we got the role admin username and password. All right. So because the role was given here admin. Fair enough. The second step is to login and get the token. So what would happen in this case? The user would hit this endpoint API of login. It will provide the username and the password. So let's do that. And this is now 403 forbidden. That means something went wrong in the authentication flow. So let's check the logs. So in the logs we can see let's check the key that was printed. So we can see the key is actually correct but it is giving me illegal B 64 character error and it seems I'm using an incorrect method when I'm calling this code base 64. Decode. So if you go to the GitHub page and this is the section that you will find where you will find all the details how to decode or encode the uh keys while verifying the token. And you can see I'm using the same method which is uh documented here hmac sh key for and this is the method that I'm supposed to use base 64 URL instead of just the base 64. So let me change all these method calls to base 64 URL and uh here as well. So let me quickly double check. All right, I will restart the application one more time. So the service is up. Let's go back to the postman and w

Original Description

Code - https://github.com/therealdumbprogrammer/jwt-token-auth-demo Spring Security full playlist - https://www.youtube.com/playlist?list=PLpxcSt9FGVVFqDPqI8m_F5SvDZTMbZ1YX --------------------------------------------------------------------------------- Secure your Spring Boot applications with JWT in this practical hands-on tutorial. Learn to: - Set up Spring Security and JWT in your project. - Configure authentication and protect REST APIs. - Generate and validate JWT tokens. - Test your endpoints. Follow along and easily implement JWT authentication for your own Spring Boot projects! 00:00 Intro 00:25 Project Overview 01:52 User Registration 11:00 JWT Documentation 16:09 Creating JWT Token 31:31 Parsing and Validating JWT 50:46 Testing ---------------------------------------------------- #spring #springsecurity #springboot #java #security #jwt
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Playlist UUjEfGki6QSKs0mL6-h2pm3Q · TheCodeAlchemist · 40 of 50

1 #java threadlocal #coding #programming #education #softwareengineer #shorts
#java threadlocal #coding #programming #education #softwareengineer #shorts
TheCodeAlchemist
2 ThreadLocal values #java #coding #codingtutorial #programming #programmer #education #shorts
ThreadLocal values #java #coding #codingtutorial #programming #programmer #education #shorts
TheCodeAlchemist
3 Immutable Design and Java Concurrency | Immutability Explained
Immutable Design and Java Concurrency | Immutability Explained
TheCodeAlchemist
4 #java concurrency and immutability #coding #programming #100k #shorts #javaprogramming
#java concurrency and immutability #coding #programming #100k #shorts #javaprogramming
TheCodeAlchemist
5 MASTER HTTP Basic Authentication in Spring Boot in Just 1 Hour | Step-by-Step Tutorial
MASTER HTTP Basic Authentication in Spring Boot in Just 1 Hour | Step-by-Step Tutorial
TheCodeAlchemist
6 #springsecurity #java #coding #programming #springboot #education #javaprogramming #shorts
#springsecurity #java #coding #programming #springboot #education #javaprogramming #shorts
TheCodeAlchemist
7 Encoding passwords in #springsecurity #springboot #java #programming #coding #security
Encoding passwords in #springsecurity #springboot #java #programming #coding #security
TheCodeAlchemist
8 #springboot #coding #springsecurity #shorts #java #programming
#springboot #coding #springsecurity #shorts #java #programming
TheCodeAlchemist
9 SECURE Your App with Roles and Permissions in Spring Security!
SECURE Your App with Roles and Permissions in Spring Security!
TheCodeAlchemist
10 #springsecurity roles & permissions #java #programming #coding #shorts #springboot
#springsecurity roles & permissions #java #programming #coding #shorts #springboot
TheCodeAlchemist
11 #java #springboot #spring #springsecurity #coding #programming #shorts
#java #springboot #spring #springsecurity #coding #programming #shorts
TheCodeAlchemist
12 Mastering Pre-Authentication with API Keys Like a PRO
Mastering Pre-Authentication with API Keys Like a PRO
TheCodeAlchemist
13 What is an Event Streaming Platform #kafka #java #coding #youtubeshorts
What is an Event Streaming Platform #kafka #java #coding #youtubeshorts
TheCodeAlchemist
14 #apachekafka #coding #code #java #javadevelopment #programming #youtubeshorts
#apachekafka #coding #code #java #javadevelopment #programming #youtubeshorts
TheCodeAlchemist
15 Running Kafka in KRaft Mode without Zookeeper
Running Kafka in KRaft Mode without Zookeeper
TheCodeAlchemist
16 #tutorial #kafka #coding #javadevelopment #java #programming #youtubeshorts
#tutorial #kafka #coding #javadevelopment #java #programming #youtubeshorts
TheCodeAlchemist
17 Kafka Producer and Consumer with Java: Hands-On Tutorial
Kafka Producer and Consumer with Java: Hands-On Tutorial
TheCodeAlchemist
18 How to Use Kafka Consumer Groups in Java | Beginner-Friendly Demo
How to Use Kafka Consumer Groups in Java | Beginner-Friendly Demo
TheCodeAlchemist
19 #kafka consumer groups #kafkatutorial #java #programming #coding #shorts #apachekafka
#kafka consumer groups #kafkatutorial #java #programming #coding #shorts #apachekafka
TheCodeAlchemist
20 Sticky vs Hash Partitioner in Kafka: Full Guide + Java Consumer Group Demo
Sticky vs Hash Partitioner in Kafka: Full Guide + Java Consumer Group Demo
TheCodeAlchemist
21 Step-by-Step Kafka Transactions Demo
Step-by-Step Kafka Transactions Demo
TheCodeAlchemist
22 The DEVELOPER'S Guide to AI and ML: Fundamentals
The DEVELOPER'S Guide to AI and ML: Fundamentals
TheCodeAlchemist
23 LLMs Explained: Tokens, Embeddings, and API Basics
LLMs Explained: Tokens, Embeddings, and API Basics
TheCodeAlchemist
24 Your first OpenAI API App - Step-by-Step Guide
Your first OpenAI API App - Step-by-Step Guide
TheCodeAlchemist
25 #chatgpt #llm #openai #tutorial #technology #tech #programming
#chatgpt #llm #openai #tutorial #technology #tech #programming
TheCodeAlchemist
26 JVM Bytecode Made Simple: Essential Concepts
JVM Bytecode Made Simple: Essential Concepts
TheCodeAlchemist
27 Master #java Bytecode #jvm #jvminternals #programming #coding #shorts
Master #java Bytecode #jvm #jvminternals #programming #coding #shorts
TheCodeAlchemist
28 #jvm operand #stack #explained #java #coding #programming
#jvm operand #stack #explained #java #coding #programming
TheCodeAlchemist
29 JVM Internals: JVM Opcodes and Java ClassFile Explained
JVM Internals: JVM Opcodes and Java ClassFile Explained
TheCodeAlchemist
30 Java Bytecode Deep Dive | What JVM Sees That You Don’t
Java Bytecode Deep Dive | What JVM Sees That You Don’t
TheCodeAlchemist
31 #java #bytecode constant pool #programming #coding #youtubeshorts
#java #bytecode constant pool #programming #coding #youtubeshorts
TheCodeAlchemist
32 Inside the JVM: Class Loading Explained
Inside the JVM: Class Loading Explained
TheCodeAlchemist
33 Java Developers: You MUST Understand These 5 JVM Memory Areas
Java Developers: You MUST Understand These 5 JVM Memory Areas
TheCodeAlchemist
34 User Signup with Email Verification 🔥 Spring Boot + Spring Security
User Signup with Email Verification 🔥 Spring Boot + Spring Security
TheCodeAlchemist
35 How to Build a Secure Password Reset Flow | Spring Security
How to Build a Secure Password Reset Flow | Spring Security
TheCodeAlchemist
36 #springboot #springsecurity #passwordreset #java #programming #javadeveloper #programmingshorts
#springboot #springsecurity #passwordreset #java #programming #javadeveloper #programmingshorts
TheCodeAlchemist
37 JWT Simplified | What Developers Must Know About Token-Based Auth
JWT Simplified | What Developers Must Know About Token-Based Auth
TheCodeAlchemist
38 #jwt #security #springsecurity #springboot #java #programming #coding #codingtutorial #codingtips
#jwt #security #springsecurity #springboot #java #programming #coding #codingtutorial #codingtips
TheCodeAlchemist
39 #jwt #jwtauthentication #authentication #security #websecurity #springsecurity #springboot #java
#jwt #jwtauthentication #authentication #security #websecurity #springsecurity #springboot #java
TheCodeAlchemist
Master Spring Security JWT in 1 Hour
Master Spring Security JWT in 1 Hour
TheCodeAlchemist
41 Want to Master Payment Processing? Watch This Now
Want to Master Payment Processing? Watch This Now
TheCodeAlchemist
42 #paymentgateways #java #coding #programming
#paymentgateways #java #coding #programming
TheCodeAlchemist
43 #education #paymentgateways #payments #paypaltutorial #shorts #programming #programmingshorts
#education #paymentgateways #payments #paypaltutorial #shorts #programming #programmingshorts
TheCodeAlchemist
44 Stripe Payments with Spring Boot | Full Hands-On Tutorial
Stripe Payments with Spring Boot | Full Hands-On Tutorial
TheCodeAlchemist
45 #paymentgateways with #springboot #java #coding #programmingshorts #programming
#paymentgateways with #springboot #java #coding #programmingshorts #programming
TheCodeAlchemist
46 #java #javacoding #coding #paymentgateways #payments #springboot #springboottutorial
#java #javacoding #coding #paymentgateways #payments #springboot #springboottutorial
TheCodeAlchemist
47 #java #coding #programming #jvm #codingtips #programmingshorts
#java #coding #programming #jvm #codingtips #programmingshorts
TheCodeAlchemist
48 Can Spring Boot Apps Really Deploy in Minutes on Kubernetes?
Can Spring Boot Apps Really Deploy in Minutes on Kubernetes?
TheCodeAlchemist
49 #java on #kubernetes with #springboot #programming #coding #programmingshorts
#java on #kubernetes with #springboot #programming #coding #programmingshorts
TheCodeAlchemist
50 Spring Boot + Postgres on Kubernetes | Cloud-Native Series
Spring Boot + Postgres on Kubernetes | Cloud-Native Series
TheCodeAlchemist

This video teaches how to implement Spring Security JWT in a Spring Boot application, covering user registration, authentication, and authorization using JWT tokens. It provides a comprehensive guide on how to configure Spring Security to use JWT tokens, generate and validate tokens, and implement custom claims and token expiration.

Key Takeaways
  1. Create a user store with Postgress database
  2. Implement user registration flow
  3. Develop authentication flow with JWT token
  4. Validate JWT token for protected endpoint access
  5. Configure Spring Security to use JWT tokens
  6. Generate and validate JWT tokens
  7. Implement custom claims and token expiration
💡 Using JWT tokens for authentication and authorization provides a stateless and secure way to manage user sessions in a Spring Boot application.

Related AI Lessons

Chapters (7)

Intro
0:25 Project Overview
1:52 User Registration
11:00 JWT Documentation
16:09 Creating JWT Token
31:31 Parsing and Validating JWT
50:46 Testing
Up next
This Cop Was Held Accountable For His Brutality! #police #lawyer
Hampton Law
Watch →