Lecture thumbnail 0:01 / 40:25 Previously, when you tried to refresh the cities page after the token is expired,

we were unable to see the effect of token expiration, right?

But actually, I have tried to refresh the page after 10 to 15 minutes,

and this is the result as a part of that.

The JWT token is still present in the browser local storage,

and we are submitting the same as a part of the request.

But as a result, it returns 401 unauthorized response.

It was expired.

But this time delay in expiration of the token

may be because of the difference in the time based on the current working time zone.

OK, we can ignore it.

It should work properly on the production time.

Anyways, the progress for us is

We got the JWT token and refresh token from the application server

and storing the same in the local storage.

Now based on this refresh token, we should be able to get the new JWT token.

So we should make a POST request quoting these two tokens to the server,

and an endpoint on the server should receive these two tokens,

verify both tokens, and generate a new JWT token.

Let’s try such that.

Let us try to create a button within this page,

somewhere near this table, to get the new token.

To do so, go to your Cities component HTML file.

So at the end of this table container,

we are going to add a button called refresh.

And it’s a regular button, but not a submit button.

So button type is button, but not submit.

And apply in the CSS styles for the same.

And when the user clicks this,

I would like to call a method called refreshClicked.

OK, let’s try to create this method in the component.

Go to the Cities component TS file.

At the most bottom, add such method.

Return type is void.

Here we have to make a POST request.

Let me add such a method in the account service first.

So go to the account service in the services folder in the Angular application.

Just like login request.

Add a method called POST generateNewToken.

And there are no arguments.

But we have to get the token, I mean JWT token, from the local storage.

So these are the keys in the local storage.

Token as well as refresh token.

We are getting the same values.

And we are making a POST request

to the mentioned URL that is

localhost 7221 API version number account

slash

the path is

new JWT token

or generateNewToken.

So we have to create an endpoint at this path.

And the object that we are supplying is

it includes both token

as well as refresh token. Both.

So we have to receive this JWT token and refresh token

at this endpoint.

And the return type is any.

Because the return value includes with the new token and

the existing refresh token.

Now copy this path.

Generate new JWT token.

Go to the account controller.

In the account controller, apart from your POST login and POST register methods,

at the end, try to add one more action method.

And this method has to execute upon receiving the POST request

at this path.

So this is the path to which we are making the request.

And for this route path we are receiving the request.

And as a part of these arguments, we should be in a position to read

the token as well as refresh token from the client application.

Let me create a model class for the same.

So go to the DTO folder in the core project.

Add new item.

Select class.

Let it be named as relevant name, for example, token model.

So we have a token model.cs file in the DTO folder

in the core project.

In which we have two properties.

Token as well as refresh token.

Okay.

We will use this model class to receive the data in the account controller.

So switch back to the account controller.

We are receiving the token model object.

Which includes with both tokens.

Now we have to start validating those tokens.

If token model is null, we have to return a response

of bad request. Optionally error message.

Okay. Assuming the

token model is not equal to null, then we will proceed here.

Then we have to get both JWT token

which is also called as access token.

Yes, JWT token is also called as access token.

So we are reading the access token or JWT token

and also refresh token. And then

we have to read this JWT token and verify the user identity.

Because in the payload of the JWT token

already it contains the user ID, right?

So we have to extract the payload from this token and extract the user ID.

And we have to check whether that ID exists in the database.

Means is it a valid ID? We have to check.

In order to do so, let me create another method in the JWT service.

So go to the IJwtService.

Yes, we are shifting different files, but we are following

the logical flow of the data. First we have added essential code

in the cities component and then account-service.ts file.

And there we are making a request, right? So that

request is being received in the account controller at this endpoint.

And here we have to extract the user details

from this JWT token. That is why we are holding the code

here and trying to create a method in the JWT service.

And after that, we will be calling that method here.

So temporarily shift to the IJwtService interface.

I would like to create a method called

GetPrinciple

from JWT token. So it receives the JWT token

and it is going to return an object of the

ClientsPrinciple type. It comes from

system.security.clients namespace. The

ClientsPrinciple object represents the user details.

I mean, an user object based on the user claims

such as user ID, email address, etc.

So if you supply the token as argument for this method,

it has to read the user details from that and return the user object

based on that. So that is why the return type is

ClientsPrinciple. And now we have to implement this method.

Go to the JwtService.cs file.

Add such a method. The same method

signature copied here.

This time it is a public method

since we have to call the same from the account controller.

And also a small change. The token may be invalid

also sometimes. So in that case, we have to return null value.

So return type is null. Even in the interface

also, the return type is nullable of ClientsPrinciple

type. Okay, switch back to the JwtService.

Here the question is, how do you extract the token

and read the payload? Already we have

installed JWT bearer NuGet package. So it provides essential

classes for the same. First we have to define

what are the validations that you have to perform on this token.

To ensure that this token is a valid token, we have to check

some validation conditions. So what are they?

Let me create all of them as TokenValidationParameters.

The TokenValidationParameters class object represents

what validations that must be performed while extracting

the token details. Here, I would like to validate the

audience and what is the actual value of the audience.

You have to mention validAudienceEqualTo

In the configuration, we have

JWT section and there we have audience value.

I mean in the app settings, JWT

audience. This is the value we were referring there.

And also we have to verify this value exists

in the token as issuer. So continue writing

the code in the JWT service. Yes, we have to

validate the issuer. So

validate issuer equal to true.

And it is asking us what is the actual value of the valid

issuer. That is as defined in the configuration.

That’s all. We are writing the configuration value here.

And this value must be matched in the payload.

And also, yes, we have to validate the

signing key. I mean signature must be verified.

And to generate the signature, there must be a key, right?

So we have to supply the same.

IssuerSigningKey equal to. Yes, it is the

symmetric key. And we are getting the key from the configuration.

And converting

the same into byte array. And that byte array will be

supplied as a key value for this class.

So based on this class, the signature gets verified at runtime

as we have discussed earlier. And we

have to write an important property, that is validate

lifetime should be false here.

It is because we are going to call this method with an

expired token. So by the time of calling this method

the token was already expired. That is why we are calling this method first

of all to verify. So we should not validate

the lifetime, means expiration time one more time here.

We already assumed that the token is expired. Actually

it doesn’t matter whether it is expired or not. So we are not

validating the expiration time here, but just verifying the audience

value, issuer value, etc. before extracting

the actual data from payload. That’s fine.

But how can you read user details from an existing token?

For that purpose, you have a predefined class called

JwtSecurityTokenHandler. You can create an object

for the same and this object is responsible to read the

user object based on an existing JWT token.

Hey, JwtSecurityTokenHandler

validate the token

and if that token is valid, return an object of

ClaimsPrinciple class that represents the current working user as per

the token. Yes, I am giving you

the actual token value, that is the parameter that is received

here. And also we have to supply TokenValidationParameters

object that contains what properties have to

be validated and what not.

So that is the second parameter here, TokenValidationParameters

Okay, so far it is trying to

read the existing token based on these validation parameters

so it validates these said properties

and also signature as well as issuer

audience values and it doesn’t validate the

expiration date and returns an object of

ClaimsPrinciple type. And also

it returns one more thing as out parameter, that is

SecurityToken. This SecurityToken

out parameter represents an instance of JWTSecurityToken

class in case if the token is a valid token.

In case if the token is invalid, then

this out parameter represents an object of SecurityToken class

or maybe null when the token is invalid.

So in order to say that the token

is valid, there are a set of conditions. First of all

the SecurityToken out parameter value

in case if it is not an object of JWTSecurityToken class

then it indicates the token is invalid.

Okay, in case if this SecurityToken is

an instance of JWTSecurityToken class

then we have to typecast the same into

JWTSecurityToken and it is referenced here

This is the new reference variable. This is of

JWTSecurityToken type. It automatically

typecast by using pattern matching syntax in C-sharp.

And also we have to check another condition.

If the SecurityToken

contains a header and that contains a property called

algorithm, that is ALG and that

must be equal to HS256

In order to represent the same, instead of hard coding HS256

we are writing security algorithms.

HMAC256 and perform

case instance to comparison. Here HMAC

SHA256 is a constant and its value is

HS256 internally. And we are going

to check that whether this HS256 matches with this

algorithm of the token. Because if you notice

that JWT token, it contains the header and it

must and should contain ALG algorithm property and its

value by default and it contains name of the algorithm

which is used to generate the hash value for the signature

and it is by default HS256 in this case.

So in the actual token that we have received, if

algorithm equal to HS256, then this condition

is true. But in case if it is not, we are adding

not operator here. So if either of these conditions

is true, I mean if the token is not a JWT

token or if it is JWT token but

the algorithm doesn’t match with this HS256

if either of these is true, that means the token

is invalid. So we can throw some exception there.

The suitable exception type for this is

security token exception. It is a predefined exception here.

Some error message.

So if we have received a token

which is not a JWT token or if that JWT

token security algorithm is not matching with this HS256

in either of these cases, the condition will be

true. So we will throw an exception because it is not a valid token.

But in case if it is a valid token,

this principal object contains the actual user details.

Already the payload contains the user details. I mean

user ID, email address etc. So those

details are represented as claims principal. You can say that

the claims principal object represents or reflects

the user details from the payload of the token. So we can

simply return the same over here. Return the principal

object. Okay. So far

we are trying to validate the token.

If the token is valid, we will get the user details from this

principal. And if it is a JWT token

and also the security algorithm is HS256,

then only we will return the principal object. Otherwise, we will throw an exception.

This is the meaning of this get principal

method. Now switch back to the account

controller. Let’s call that method over here. Hey

JWT service, get principal object

based on this existing token. And you are going to return an object

of claims principal type, right?

Make sure you imported that namespace.

System.security.claims namespace.

And it is nullable. So we have

to check if the principal object is null here.

That indicates the user object is not found in the payload.

So we will return a bad request response to the client.

Okay. In case if

the principal object is not equal to null, then we will proceed here.

We have to extract the email address from this claims principal.

What about the payload properties that we have

added earlier while generating the token? All those payload properties

are available in this claims principal. One of them is

user ID, email address as well. So we are

trying to read. Hey principal,

find the first value of which type?

Claim types dot email address.

It is a predefined type and it returns the value

from the payload, the email address value.

And we are extracting the same here.

See, while we were generating the token

as a part of the JWT service,

see here, we have included some claims, right? One of them

is user email address. So we are going

to extract the same over there. Okay, sorry, it is

name identifier, right? We have added the same here.

The email address value is added as name identifier.

So let’s get back the same here. In the account

controller, claim types is name identifier.

So it contains the actual value of email as

added earlier. Then from the user manager,

we have to find the particular user based on

email address and use await to call it because

it is a synchronous method.

So it returns

an object of application user class and

it is nullable. So we have to check a condition here.

If the user object is equal to null, that means

the email address value that you find here is an invalid value.

Okay. In case if it is not equal to null, that

indicates the user object is found based on the email address. That is fine.

And then we have to check another condition. If the

refresh token value is matching or not.

Already we have stored the refresh token value in the users

table. So the same is reflected in the user object

over here. If this doesn’t match with the refresh token

that is received here as a part of the method,

that is from the token model,

we have refresh token, right?

This token model dot refresh token represents the refresh token

that was supplied as a part of the request.

And this user dot refresh token represents the refresh token which was

stored in the database table, in the AspNetUsers table.

So we have to check whether they match.

If they don’t match here, that is not equal

to otherwise or if the

refresh token expiration date time is already completed.

See the JWT token is already expired, I know.

But if the refresh token is also expired, the user

must be able to re-login through login page. So we don’t accept

it here. We cannot regenerate the JWT token

without re-login then. So we have to check

if that refresh token expiration date time is

already completed, that means less than or equal to the

current system time. If either of these

cases happen, then we have to return a bad request result.

See, if no user is found

at this email address which was read from the payload of the token,

that means if the user is null or if the

refresh token from the request doesn’t match with the one from the database

or if the refresh token is also already

expired, in either of these cases, we cannot

regenerate the JWT token based on the refresh token.

So we will return a bad request, optionally error message,

for example, invalid refresh token.

Okay, so if this condition doesn’t match,

means the user object is found and also

the refresh token value was found in the database table,

that is in AspNetUsers table, and also refresh token

is not still expired. In that case only we will

reach here. So here is the correct place for generating

a new token. Hey JWT service, create a new

JWT token based on the existing user object.

So the same process as performed earlier.

Just like at the time of login we have regenerated the JWT

token, the same process happens. So we will get

authentication response there. Of course,

there we are generating both JWT token and

refresh token as well. So we are getting both new tokens.

So that is why we have to re-update the refresh token

in the users table. In the user object, our

new refresh token equal to the newly generated

refresh token, and also its

expiration date time. And also, in order

to reflect these changes back to the actual database table,

we have to call, hey user manager,

update this user. Okay, then the database gets

updated. I mean, in the AspNetUsers table, for the

particular user, the refresh token as well as refresh token

expiration date time, both columns gets updated.

After that, we can return the authentication response

back to the client. So overall, if you

ask me to review the code one more time, we are receiving

a request at this path, verifying whether we have

received the refresh token as well as JWT token.

Okay, these two statements are unnecessary. We could

have write token model dot JWT

token directly. That’s fine. So based on this

JWT token, we are extracting the claims principle object,

which contains all the data from the payload that we have added earlier.

For example, we can expect that it should include

the person name and email address. Of course, this user

ID as well. Particularly, we are trying to read the email address

value from that, and we are trying to fetch

the data from AspNetUsers table based on the email address.

So if that email address is valid,

then we should get the actual user object into this variable, right?

So it should not be null, and also refresh

token should match, and also the refresh token should not be expired.

In case if the user object is null,

I mean if the email address is invalid, or the refresh token

doesn’t match with the one that is received from the request,

or the refresh token is expired already,

if either of these, then we will return a bad request

as response, that is 400 bad request.

But if everything is good, we will reach here,

and we will try to generate a new token, because we don’t

have any reason to reject the request.

After you call this, as a part of this method, we are regenerating both

tokens, both JWT token and a refresh token.

We are going to update the newly generated refresh token

over here in the database table, and then after that

we are giving the same as response.

So this is the process, and we are going to invoke this particular

endpoint at this address from account-service.ts

file. So in the Angular code

we are going to make a POST request, and trying to submit the token

as well as refresh token, both. That is fine.

Now we have to make sure whether we are calling this

POST generate a new token method in that button click.

So go to the cities-component.ts file. Here

we have to call that method. This method executes when the

refresh button is clicked, right?

Oops, here account-service is not injected. Let me inject the same

there. So in the constructor of the cities-component

let us try to inject the account-service.

And then

come back to the same method, refresh clicked.

Now we can access the account-service. Hey account-service

POST generate a new token method

and no need of any arguments. It takes the tokens automatically

from the local storage. Just try to subscribe to the same.

As usual, next, error

and complete. Always make sure you

mention the data type for all the parameters, otherwise you might get

compilation errors for the Angular code. If you don’t

know the data type, you can just write any data type.

So as a response, what are we trying to get?

Importantly, we are getting two tokens, that is the regular JWT

token as well as refresh token.

Just like we will get new tokens after login,

so in the same way, we will store them in the local

storage. That is, token equal to

the token from the response.

Here token represents the JWT token.

Actually, you should write the properties as defined

in the authentication response class. See here, token and

refresh token. So you can read the same.

Okay, we have successfully received

the new tokens and stored the same in the local storage,

overwriting the older tokens. And after that,

we have to refresh the cities data. So we can just call

loadCities method and as the code written in the loadCities

method earlier, it makes a fresh request

to api slash cities. See, this loadCities

method is trying to call getCities and we are making a fresh

get request to api slash cities. And this

time, as a part of this, we will use the newly generated

token. See, we are reading the token.

So this gets the newly generated token from the local storage, which

we have got after refreshing. That’s fine. Run this

application and see. So step one is first login.

Before that, clear all the

things from the application local storage and

login. So we have got the first token

and assume that after some time, this particular JWT

token got expired. So then we will be unable to read

the cities data. If you refresh the page,

assume the page is not working.

Still we have the same token, but the existing JWT token

is expired. Assume that. So

we are needing to get a new token. That is why we are just clicking

on refresh button over here. Oops,

we are getting 400 response. We

made a request to generate a new token,

but we are getting 400 response.

Let’s add a breakpoint there and

see what’s happening. In the account controller,

add a breakpoint in this generate a new JWT token method.

Click refresh. Yes, the breakpoint

hits. I mean the endpoint execution started.

The token model includes with the refresh token and the existing JWT

token both. Now the token model

is not equal to null, so we will not return a bad request

and we are able to read the claims principal object from the existing

token successfully. So it contains the

claims identity, that is the person name

and is authenticated equal to true

and we have got the JTI IAT

ID, audience and other properties

as you can see. So we are reading the email address.

Now this email address value is not fetched correctly.

Let us try to rewrite.

So we are not able to read this email address by using

name identifier. Let’s do one thing.

Switch back to JWT service. Let me add one more

identifier here. I mean another claim

that is claim types.email

and the actual user email value.

So this value gets included as a part of the JWT

token and we will be able to read this

email address value from the token. So in the account controller

the claim types.email, we should be able to

get the email address value. Run again.

First we will try to login.

Clear the local storage first to avoid confusion.

Click login with the right username and password.

So we have successfully logged in and we have got the token.

Remember this refresh token begins with SgM

and after refreshing we should be able to get a new refresh

token as well as a new JWT token.

Remember at least few characters of this JWT token.

For example it contains EYJZ.

OK. Click refresh button here.

Again we made a request to generate a new JWT token.

We have received the JWT token

as well as refresh token. And this time

we are able to read the email address value i.e. harsha at example.com

And based on that email address

we are able to get the user object from the database table

i.e. from AspNetUsers table. And then since the user

object is not equal to NULL and also the refresh token

matched with the database data and also refresh token

is not still expired. It is valid for 60 minutes.

So this condition is false. So this bad request is not

returned. And we are trying to generate a new token.

Yes, we have got the new token this time in this

authentication response. And that gets updated in the database

table. And return the same as response.

Yes. Now we have got a new token.

See this refresh token and

this JWT token differs from the previous one.

So if you notice the network tab, we made

a request to generate a new token. And it’s a POST request.

Response status code is 200.

And the response includes with the person name, email, as well as the

newly generated tokens. That is both

refresh token as well as newly generated JWT token.

And after that, since you called load cities

method in the Angular application, it is trying to make a request to

API slash cities with the newly generated token. So it

includes with the request headers, authorization

and it sends the newly generated token over here.

And it is valid. So that is why we have got the cities

data as response. So in the users perspective,

as soon as the token is expired, he can click on this refresh

button so he can get the new token.

But in the real world production scenarios, we can make the same

process as automatic. For example, as soon as the

user opens this cities page, even without clicking this button

also, the system has to automatically check whether that token

is already expired. In case if it is expired, based

on the refresh token, it has to regenerate a new token. So

the same process should be happened automatically without an explicit button

click. In this application, to avoid the confusion

to see the actual process of refreshing the token, we made

the user interface in this way, that is through an explicit button

click. In real world applications, the same can be processed

automatically, that is regeneration of the token

based on the refresh token as soon as it got expired.

You can do the same with a middleware, for example.

You can add a custom middleware and check the token. If the token

is expired, regenerate the same if the refresh token

is valid. Okay, we are not doing it here.

Overall, this is the way how do you handle the JWT

and refresh tokens to improve security and

handle authorization for the users.