Get the source code for this video for FREE → the-dotnet-weekly.ck.page/jwt-auth Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt If you run into any issues while trying to implement this, I made two mistakes in the video: - At 16:00 it should be one call to `UseAuthentication` and one call to `UseAuthorization` - `JwtBearerOptionsSetup` should implement `IConfigureNamedOptions`
Milan! suppose we have this api having authentication & authorization as you did returning token on success login. now i want to consume this token in my front-end application developed using net core, which will use this token to authenticate and authorize user. question is how should we will implement setting for front-end application so it get logged/signin on token and authorize user accordingly and auto add token in api call header.
Nice tutorial, especially the solution approach with options is quite pro. For those who try to use the example code with NET Core 7.0 will not have their JwtBearerOptions initialized thus token validation will fail. To solve the issue JwtBearerOptionsSetup must derive from IConfigureNamedOptions. JwtBearerOptionsSetup : IConfigureNamedOptions public void Configure(JwtBearerOptions options) { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = _options.Issuer, ... }; } public void Configure(string? name, JwtBearerOptions options) => Configure(options);
@tosunabi1664 thank you very much. I'm wondering I did the same in this video, I know it isn't wrong but it can't validate token. When I used IConfigureNameOptions and it worked
What a tutorial !!!! Lacking words to describe this ,everything is professionally done !! I like the way you handle errors ,I liked the way you use DI and they way you did set up the JwtBearerOptions instance ,thanks buddy .
Thanks, Milan, This video helped me to integrate the JWT-based authentication in Clean Architecture. I searched a lot of articles and videos but this one is great 🚀
I never leave comments on videos, but this one absolutely deserves it. Great tutorial, not the average ‘just get it done’ attitude. So much effort into doing it cleanly and actually teaching proper techniques. Thank you. I’m interested in learning more on the command implementation done at 0:50 and your overall project structure and approach. Are the any further videos on this project?
I talk about CQRS often: - ruclips.net/video/vdi-p9StmG0/видео.html - ruclips.net/video/85YbMEb1qkQ/видео.html You can search for "cqrs" on my channel, a bunch of videos will show up. Also many videos around project/solution structure.
Kindly smashed the ring bell button too. What about token expiration? Should we use refresh token endpoint or there is sliding expiration if we use this method?
We can (and should) also configure that through app settings also I would leave the refreshing to the frontend. The easiest is they can get a new token. Adding refresh token support requires more work.
@@MilanJovanovicTech Sorry to jump in :) requiring a new token in a real application would require us to send again username\password (so we would need to store them somewhere in the client application..not ideal)..better to use the refresh token flow
I came looking for copper but found gold. Amazing content, that helps a lot. I also have a question. What is in your opinion best way to tackle authentication in microservices environment and/or what are the best sources to look for?
For people starting to move into this space, this is an excellent introduction to aspnet security. Well done Milan! With JWT bearer tokens, a word of caution - please consider your bearer token storage particularly in your browser based client side applications. Current recommendations is to move away from clients having any access to the JWT bearer tokens and instead use cookie based HTTPOnly cookies through patterns like BackEnd For FrontEnd (BFF). Again I want to take nothing away from this amazing video!
@@MilanJovanovicTech In the limited amount of space we have in a chat to discuss a very deep problem sure! Firstly, completely agree that many applications are storing JWTs client side. I have built several systems in that way :D The generalized problem that client side storage introduces is how to protect the JWT which is a plain text password with a short lifespan. The general two options used to date are Local Storage and Cookie storage. In both approaches, malicious JavaScript can extract the JWT bearer token from the user's session storage and use it to attack the protected resource. The problem gets worse when the refresh token is also sent to the client side to support silent refresh which I still commonly see. This is even worse because it removes the short lifespan assurances provided by the JWT. As such, the current OWSAP recommendation is to never provide the client with the bearer or refresh token but instead use HTTPOnly cookies. This particular characteristic of the cookie means that JavaScript cannot access the cookie (with the exception of a browser level security vulnerability)
The OWASP link is of particular importance because it talks through the specifics of proper session cookie storage and the additional requirements that go along with that. These are characteristics implemented in BFF frameworks such as Identity Server's implementation.
@@VastSolar while jwts are text and are completely modifiable, they also have server side validation to prevent tampering using standard public key infrastructure signing techniques. This means a valid jwt can only be created by a system with access to the private key. Encryption of jwt data is also possible.
This is great for anyone want to go into identity It will be very good if you continue it as a serie with openid dict 3 and extend it to oauth 2 and openid connect
Milan, I don't know why, but for some reason the JwtBearerOptionsSetup class Configure method was never called for me, if I followed your tutorial. The class had been instantiated, the constructor was called, but the not the Configure method. After I changed the interface from IConfigureOptions to IConfigureNamedOptions, then the Configure method called succesfully and works without any issue. :)
Oh, I have been trying to figure out for hours. I could configure authentication directly from startup but Milan's approach was not working. Now IPostConfigureOptions has worked, Thanks you both for this comments. Also Milan it would be nice to share your code from github or another source control website, it would be better for us to directly look into working version of it. Anyways thx for your awesome tutorials
Join more than *42,000+ .NET engineers* already reading my weekly newsletter. One actionable tip, every Saturday, less than a 5-minute read: www.milanjovanovic.tech/
Unless I missed you haven't showed on the video when you rigstered JwtProvider. Great video, I've done it myself as Infrastructure service without Mediator. I guess another small / quick video interesting to many people might be registering via Facebook or / and Gmail.
@@MilanJovanovicTech Forgot about that . but for people that came here for the 1st time looking for JWT implementation this comment might be useful ;-)
02:07 - You're using ICommandHandler interface from the Application.Abstractions.Messaging namespace. Can you please provide us with the implementation of the interface?
Hey Milan! Nice solution! Is this approach good for production? Are the signing credentials secure enough? I've heard that a signing certificate needs to be present, however, I don't know how this is implemented. Thanks!
@@MilanJovanovicTech I'm asking for my bachelor thesis. My current implementation uses Auth0, but I want to build my own solution some day, just for the sake of it and understand the whole process. I'm still a junior dev and many of the solutions like Auth0 abstract much of the process and it itches me from the inside to learn it all haha.
Don't put sensitive info in the token. Token being short lived should be all you need, as it just needs to exist to perform api requests, not interface with the system to finagle auth implementation. The token is the auth, and shouldn't need to be used except for transactional requests.
Great explanation for the generation of the token, kinda lost in the DDD because it was never my cup of tea but thanks in adance for the great tutorial.
Thank you for video. I have a question, why you decide to make custom authentication (and authorization in future) instead of using something as Identity Server for example?
Hi Milan. Nice video. I just like to ask if you have another one with the best practice to refresh the token before the original one expires. Regards from the land of Maradona and Messi
Yet another great video, really breaks down simply what the JWT token is and all the options. Random question, how does your IDE show the values of your variables when debugging within the text editor? Seems very convenient compared to the separate windows.
Is this a video in a series? I think I'm missing some basic setup to get this working. I'm trying to learn this, have an understanding of database migrations, controllers and REST api's but I don't understand how the interfaces you implement can execute the code of the class
Great video! Thank you so much! This would have been even better if you had ditched Clean Architecture in favor of simple architecture; dare I say Minimal APIs? Clean Arch forces you to create way too many files and abstractions to do a trivial task and I've got PTSD from it.
Do you have a video when you started this project from beginning ? I found you have already written a lot of codes. I am a newbie, and I found you have great contents.
Hi Milan, following your technique to setup JwtBearerOptions through ConfigureOptions gives me a www-authenticate: Bearer error="invalid_token",error_description="The signature key was not found" error. I still need to add the configuration as a AddJwtBearer method parameter in order to get it working. It's a .NET 7 web api project.
Awesome video! Correct me if I'm wrong, wouldn't it be a good idea to create an extension method for the Services? ex: builder.Services.ConfigureJwtSetup(), then the said ConfigureOptions will just be invoked there (well if those two are tightly coupled).
Hello! I encountered your videos on permission authorization and tried to return to the start of this 'series' link by link. This one seems to be the starting point, but, for example, throughout the video you use the Abstractions namespace from the solution. Am I right to assume that, for example, ICommand interface is your own written abstraction? Or is that some common logic that I'm just not familiar with? Being a little confused trying to follow along.
Hi, great video. I would just like to have one question. Why do you separate the login request and command? why doesn't the controller just take a command as a parameter?
Correct me if im wrong... The web tokens are stamped into http secure cookies, correct? So the browser context which has the proper cookies has authorization, but the frontend doesnt have any way to indicate that it has auth cookies...right?
Fantastic video! I'd love to see the using of the JWT expanded a little. For example yes they are a member and have successfully authenticated through the login endpoint. But they do not have permission to access GetMember endpoint based on claims (think it would be here that this differentiation would be set?). Would [Authorize] be un changed and the blocking of endpoint usage be within the endpoint method perhaps.. Anyway once again fantastic video had me captivated.
Hi Milan, great video. I am having a small issue implementing this though. I did not see in your video the adding of the service IJwtProvider to the program.cs. When I add these steps to my application I get a service issue on the JwtProvider. Any quick suggestions would be appreciated.
Don't worry there were 2 issues. 1 was the IConfigureNamedOptions Implementation on the JwtBearerOptions and the service issue i resoled by just making the jwt token generation happen inside the authorisation controller and removed the JwtTokenProvider Class. All works now so thanks for the video. If you have a quick idea as to why the generate method works in the JwtTokenProvider class for you and not in my case it would be great to learn why.
@@MilanJovanovicTech Yes thank that is how I figured out an error I was having with failed JWT signature. I did try the scoped service but was getting a life cycle determination error. Token Generation is cruelty working as part of the Auth Api so will leave it there for now. Thankyou
Thank you very much for that! Can you say when should we use symmetric and when asymmetric keys to create JWTs? Currently we use symmetric, the server creates the JWT and sends it encrypted to the user. When the user sends it back, the server decrypts and checks it. The symmetric key is securely stored on the server. Do asymmetric keys have any advantages here?
Ideally, you won't implement any of this on your own. There are excellent third-party authentication services that implement this much more securely than what I showed in the video.
@@MilanJovanovicTech Because the application layer cannot depend on the infrastructure, so calling the interface directly from the infrastructure would break the rule, right?
@@MilanJovanovicTech Thank, you, i found my problems, issue with postman, after resolving my problems with postman, now works perfectly. Thank you for this content and for your answer.
What are your thoughts of storing refresh and access tokens in localstorage? I have implemented refresh token rotation, and I do store the tokens in localstorage. So if the request is 401 etc I send to token/refresh and get new token pair and continue with the original request. But I am reading a lot of mixed information, some say its considerably more safe to store it in httponly cookies. I would appreciate your input on the implementation. Its a system where users login with a personal id. So its a bit sensitive, maybe httponly cookies is better then?
@@MilanJovanovicTech Okay, thank you :D I will go for the implementation I have right now but will consider switching before deploying. Appreciate the answer :)
@@sonnyskold5634 Hi! Since the refresh request will inherently always need the refresh token (and the refresh token will need to be sent to the UI in the first place), there really isn't a way to keep it safe from bad actors; as is generally the case with anything on the frontend. If you want it safe, keep it server side. The safety in these tokens comes from the hashing. It's actually pretty neat if you look up how it works, basically all the parts of everything that's encoded get meshed together and most stay on the server so the client knows very little about from what the token is generated. In terms of how to handle it, it depends on the concerns of the application. You'll often see websites have a "User inactive, you will be signed out in 'x' seconds, click to refresh" popup. I'm not certain but I assume that's just doing the refresh haha. Regardless if you're doing automatic token refresh, you should really do something to have either your users opt in or let them know that's what is going on for ethical considerations. You do want to make sure you're rotating your refresh tokens. You don't want any to be long-lasting. That said, what you listed works fine haha. I've done that in plenty of personal projects. For something more professional you should really do the pop-up.
I just looked at Jwt authentication and was wondering: I wanted to use this for authentication API users where I supply an 'apikey' in the form of a Jwt. But then I want users to be able to use this token a long time (it will be configured in some backend services), but still have the ability to revoke it when needed. Am I correct in thinking the only way a Jwt can be revoked is by changing the Secret that is used to validate tokens, or I should store the token in the Api to have a revocationlist of tokens that I don't want to be used anymore. Maybe this is not what Jwt was intended for but with an API service you would like to give users access, be able to change what access they have (which endpoints they can call) and also either extend or revoke their access. This is not something a Jwt does out of the box unless you program around this. I tend to see a Jwt as something you can use to give shortlived access (hence the expiration) and during that time give access to a fixed set of resources, the claims (roles/policies) in the Jwt. It's handy that any endpoint can validate the token and give access to resources based on the claims inside this token without the need to go to some backend database. In my case we have an API that has several endpoints, let's say Company, Contact, Order and some users might not have access to Order so the Claims could quikly block users there. But then a user might have access to Company A, and **not** Company B, thats access information that cannot be stored in the Jwt and has to live elsewhere...right? But then when I have to store data elsewhere anyway, why not store as much of it elsewhere instead of in the Jwt...**I'm thinking of the Expire date here ** why store that in the token when I could also put in in the database, and even have the ability to extend it without having to give the user a new token. @Milan Do you have some place to discuss this with others outside of the RUclips comments?
@16:10 - you added app.UseAuthentication(); twice even though use said one should be app.UseAuthorization(); (lines 99 and 101) With that mistake, why did it work anyway?
@@MilanJovanovicTech Thanks. By the way, your source code is slightly different than the codes in the video. Did you make some improvements to it? For example, JwtBearerOptionsSetup is implemented IPostConfigureOptions instead of IConfigureOptions in the source code.
That's a tough one, the short answer is no. But you can somehow store the token and check it on every authentication request, which is stupid and degrades performance. One option is to give tokens a short lifetime. Another option is to code your client side code to request a new token when a user does an action like that.
A lot these videos and post of generating jwt tokens are out there but interestingly none on how to use the refresh token on a web client especially SSR client
hi, If authorization fails and you get this error : bearer error="invalid_token", error_description="the signature key was not found"; In JwtBearerOptionSetup class implement IPostConfigureOptions
Milan, I get this exception whe try to create SymmetricSecurityKey: IDX10720: Unable to create KeyedHashAlgorithm for algorithm 'HS256', the key size must be greater than: '256' bits, key has '128' bits. (Parameter 'keyBytes')) I believe the problem is somewhere in UTF8. Could you advise how to fix this?:
@@DENDYTWOO No reason to be, I never discriminate on knowledge. 😁 IDP = IDentity Provider What would that be? - Identity Server - Active Directory - Auth0 - KeyCloak - Firebase Authentication
@@MilanJovanovicTech I really appreciate you answering my question. I do not know what I should answer your question about IDP, but now I know what it means. You are smart and kind, thank you for the answer and for your videos
Hello, I believe I have followed this tutorial perfectly a number of times and have created a solution just for testing it, though I am always hitting the same issue. When testing in Postman, I am getting the following error in the `WWW-Authenticate` header: `Bearer error="invalid_token", error_description="The signature key was not found"` - do you have any ideas why this may be happening?
Yes, I do believe I mistakenly configured JwtBearerOptionsSetup to implement IConfigurOptions, and it should be IConfigureNamedOptions or IPostConfigureOptions. Also, at around line 105 in Program.cs, I have UseAuthentication two times. Where one of those should be UseAuthorization
@@manofqwerty RUclips is weird like that sometimes. Thanks for letting me know, I'll pin the explanation for anyone else that runs into the same issue.
Using the options pattern within your startup configuration is an overuse of the pattern. This will get refactored into an extensions method where you simply pass configuration into a static method where the JwtBearer options can be configured. Also the OptionsSetup folder is not very useful or extensible for scaling the app. Instead I would add a Middleware folder in the Api project (Gatherly.App) then add folders as you create more startup extensions (Auth, HealthChecks, OpenApi, Telemetry, Validation, Etc.)
Hi Milan, what about if i take this token and called specefic function with parameter not allowed to me ? how i can prevent it to happen specially from postman interface. Thanks
@@MilanJovanovicTech if you take the jwt token and make request from postman if will be accepted even if this api is acepefic for 1 user, what shall i can do to prevent this to happen? i hope you can get what i means
in another way lets supposed there is api with email id to get all email info. anyone can use this api through postman with valid jwt token with random email id to get email info without he has the access to this email itself.
@@ramysamir1987 You need to add the concept of resource authorization to that. Based on the JWT you can know WHO the user is, and determine if they can access that specific email
@@MilanJovanovicTech i tried it out but it does not seem to work, after some debugging it looks like the JwtBearerOptionsSetup class does not run at all, seems that if i extend IConfigureNamedOptions instead of IConfigureOptions it works.
@@pseudocoffee4829 , Thanks for posting this. I was seeing a similar problem and hardcoded the config as a work around. I kept both interfaces and simply called the original Configure(options) from Configure(name, options).
Get the source code for this video for FREE → the-dotnet-weekly.ck.page/jwt-auth
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
If you run into any issues while trying to implement this, I made two mistakes in the video:
- At 16:00 it should be one call to `UseAuthentication` and one call to `UseAuthorization`
- `JwtBearerOptionsSetup` should implement `IConfigureNamedOptions`
Milan!
suppose we have this api having authentication & authorization as you did returning token on success login.
now i want to consume this token in my front-end application developed using net core, which will use this token to authenticate and authorize user.
question is how should we will implement setting for front-end application so it get logged/signin on token and authorize user accordingly and auto add token in api call header.
Thank you for this great tutorial.
could you please explain how JwtBearerOptionsSetup` should implement `IConfigureNamedOptions` ?
Hey mate! Thanks for your videos!
Would you be able to make the same video to .NET 8 version?
Thanks in advance!
Thanks for source code :)
@@YehorBachurinDev You're welcome!
Nice tutorial, especially the solution approach with options is quite pro.
For those who try to use the example code with NET Core 7.0 will not have their JwtBearerOptions initialized thus token validation will fail.
To solve the issue JwtBearerOptionsSetup must derive from IConfigureNamedOptions.
JwtBearerOptionsSetup : IConfigureNamedOptions
public void Configure(JwtBearerOptions options)
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = _options.Issuer,
...
};
}
public void Configure(string? name, JwtBearerOptions options)
=> Configure(options);
I do believe it's noted in the pinned comment 😅
@@MilanJovanovicTech I saw after posting.
@tosunabi1664 thank you very much. I'm wondering I did the same in this video, I know it isn't wrong but it can't validate token. When I used IConfigureNameOptions and it worked
What a tutorial !!!! Lacking words to describe this ,everything is professionally done !! I like the way you handle errors ,I liked the way you use DI and they way you did set up the JwtBearerOptions instance ,thanks buddy .
Wow, thank you very much!
Thanks, Milan, This video helped me to integrate the JWT-based authentication in Clean Architecture. I searched a lot of articles and videos but this one is great 🚀
Glad it was helpful!
One of the best tutorial I have watched so far in any topic, very clearly explain all you need , well done
Glad it was helpful!
I never leave comments on videos, but this one absolutely deserves it. Great tutorial, not the average ‘just get it done’ attitude. So much effort into doing it cleanly and actually teaching proper techniques.
Thank you.
I’m interested in learning more on the command implementation done at 0:50 and your overall project structure and approach.
Are the any further videos on this project?
I talk about CQRS often:
- ruclips.net/video/vdi-p9StmG0/видео.html
- ruclips.net/video/85YbMEb1qkQ/видео.html
You can search for "cqrs" on my channel, a bunch of videos will show up. Also many videos around project/solution structure.
Thank you Milan! Another useful video and excellent quality of the content. Cannot wait to see the Authorization part :)
Coming soon!
Kindly smashed the ring bell button too. What about token expiration? Should we use refresh token endpoint or there is sliding expiration if we use this method?
We can (and should) also configure that through app settings also
I would leave the refreshing to the frontend. The easiest is they can get a new token. Adding refresh token support requires more work.
@@MilanJovanovicTech Sorry to jump in :) requiring a new token in a real application would require us to send again username\password (so we would need to store them somewhere in the client application..not ideal)..better to use the refresh token flow
Love that bright screen warning :)
You're welcome 😅
I came looking for copper but found gold. Amazing content, that helps a lot.
I also have a question. What is in your opinion best way to tackle authentication in microservices environment and/or what are the best sources to look for?
I would explore some existing platforms that can solve this problem, so I don't have to do it myself. Auth0, Identity, KeyCloak, etc.
Thank you Milan! Excellent quality of the content.
You're very welcome :)
Great vid as always!
one small mistake at 16:00 you added the Authentication middleware twice and not the Authorisation middleware
Sharp eyes! Yes, I missed that during recording, but fixed it later (otherwise it wouldn't have worked)
you're an artist, man! this is pure art.
Thanks a lot! 😁
For people starting to move into this space, this is an excellent introduction to aspnet security. Well done Milan! With JWT bearer tokens, a word of caution - please consider your bearer token storage particularly in your browser based client side applications. Current recommendations is to move away from clients having any access to the JWT bearer tokens and instead use cookie based HTTPOnly cookies through patterns like BackEnd For FrontEnd (BFF). Again I want to take nothing away from this amazing video!
There are still so many applications storing JWTs client side. I'm not that good at frontend to see why this is a major issue. Care to explain?
I suppose this is because it allows tinkering with token (data stored in token). While cookie stores only ID by which you get all the data.
@@MilanJovanovicTech In the limited amount of space we have in a chat to discuss a very deep problem sure! Firstly, completely agree that many applications are storing JWTs client side. I have built several systems in that way :D The generalized problem that client side storage introduces is how to protect the JWT which is a plain text password with a short lifespan. The general two options used to date are Local Storage and Cookie storage. In both approaches, malicious JavaScript can extract the JWT bearer token from the user's session storage and use it to attack the protected resource. The problem gets worse when the refresh token is also sent to the client side to support silent refresh which I still commonly see. This is even worse because it removes the short lifespan assurances provided by the JWT. As such, the current OWSAP recommendation is to never provide the client with the bearer or refresh token but instead use HTTPOnly cookies. This particular characteristic of the cookie means that JavaScript cannot access the cookie (with the exception of a browser level security vulnerability)
The OWASP link is of particular importance because it talks through the specifics of proper session cookie storage and the additional requirements that go along with that. These are characteristics implemented in BFF frameworks such as Identity Server's implementation.
@@VastSolar while jwts are text and are completely modifiable, they also have server side validation to prevent tampering using standard public key infrastructure signing techniques. This means a valid jwt can only be created by a system with access to the private key. Encryption of jwt data is also possible.
You're the best tutor I ever had, Thanks a lot buddy!
You're most welcome! :)
As always I learned a lot...can't wait for the next video.💯❤
Coming out on Friday 😁
This is great for anyone want to go into identity
It will be very good if you continue it as a serie with openid dict 3 and extend it to oauth 2 and openid connect
I will likely pivot into some sort of Identity Provider
Absolutley subscribed! Amazing content delivered so well. Thank you.
Welcome aboard!
Milan, I don't know why, but for some reason the JwtBearerOptionsSetup class Configure method was never called for me, if I followed your tutorial. The class had been instantiated, the constructor was called, but the not the Configure method. After I changed the interface from IConfigureOptions to IConfigureNamedOptions, then the Configure method called succesfully and works without any issue. :)
Oh, replace it with IPostConfigureOptions! Forgot to mention that 😅
I made a mistake, and was too lazy to go back and re-record
@@MilanJovanovicTech oh, okay no problem. :) thank you
Oh, I have been trying to figure out for hours. I could configure authentication directly from startup but Milan's approach was not working. Now IPostConfigureOptions has worked, Thanks you both for this comments. Also Milan it would be nice to share your code from github or another source control website, it would be better for us to directly look into working version of it. Anyways thx for your awesome tutorials
@@chesterapavliashvili1533 you are welcome :)
Join more than *42,000+ .NET engineers* already reading my weekly newsletter.
One actionable tip, every Saturday, less than a 5-minute read:
www.milanjovanovic.tech/
Bright screen warning 👍
It hurt my eyes, so I figured I'd warn you guys 😅
The IOptions thing was new, thanks !
Glad you learned something new 😁
Unless I missed you haven't showed on the video when you rigstered JwtProvider. Great video, I've done it myself as Infrastructure service without Mediator. I guess another small / quick video interesting to many people might be registering via Facebook or / and Gmail.
I have a piece of code using Scrutor which registers it automatically
@@MilanJovanovicTech Forgot about that . but for people that came here for the 1st time looking for JWT implementation this comment might be useful ;-)
Hi Milan,
Thanks for sharing your knowledge with us. It would be really great if you create one guide for handling refresh token
Noted!
Thank you Milan, love your videos
Glad you find them valuable :)
Good content i think one you miss about how to refresh token...
Didn't want to tackle it
I recommend creating a solution from scratch since it is too confuse to understand cause you have already lots of code in your solution.
Most people are able to follow
02:07 - You're using ICommandHandler interface from the Application.Abstractions.Messaging namespace.
Can you please provide us with the implementation of the interface?
Take a look at this video: ruclips.net/video/vdi-p9StmG0/видео.html
@@MilanJovanovicTech Thanks Milan, now I got it! Nice videos btw!
Hey Milan! Nice solution! Is this approach good for production? Are the signing credentials secure enough? I've heard that a signing certificate needs to be present, however, I don't know how this is implemented. Thanks!
Why not use an external Identity provider and not have to think about it?
@@MilanJovanovicTech I'm asking for my bachelor thesis. My current implementation uses Auth0, but I want to build my own solution some day, just for the sake of it and understand the whole process. I'm still a junior dev and many of the solutions like Auth0 abstract much of the process and it itches me from the inside to learn it all haha.
Don't put sensitive info in the token.
Token being short lived should be all you need, as it just needs to exist to perform api requests, not interface with the system to finagle auth implementation. The token is the auth, and shouldn't need to be used except for transactional requests.
Great explanation for the generation of the token, kinda lost in the DDD because it was never my cup of tea but thanks in adance for the great tutorial.
Not much DDD here, but I needed this released before I could tackle Permissiom Authorization
Where does this video continue from? Is there a video explaining how you got to this current outline (constructing gatherly)
All the previous videos on the channel
Thank you @MilanJovanovicTech
But are there any previous videos describe this project (Gatherly) from zero
There isn't one
@@MilanJovanovicTech I just need to know the content of the Result class, could you provide it for me please
Thank you for video. I have a question, why you decide to make custom authentication (and authorization in future) instead of using something as Identity Server for example?
I wanted to show the concept, and I also use some IDP on a real project. I'll make sure to cover that
@@MilanJovanovicTech It would be great to know your plan and a summary of future videos)))))))
Very interesting video. Waiting for next. Special thanks
Coming right up!
Thank you so much. Great topic🤩🌹
Glad it was helpful!
Hi Milan. Nice video. I just like to ask if you have another one with the best practice to refresh the token before the original one expires. Regards from the land of Maradona and Messi
I didn't cover refresh tokens. Sending my regards from Serbia, to Argentina :)
Yet another great video, really breaks down simply what the JWT token is and all the options.
Random question, how does your IDE show the values of your variables when debugging within the text editor? Seems very convenient compared to the separate windows.
I'm not sure, it's either the latest VS version or ReSharper
JetBrains Rider has this feature by default
Is this a video in a series? I think I'm missing some basic setup to get this working. I'm trying to learn this, have an understanding of database migrations, controllers and REST api's but I don't understand how the interfaces you implement can execute the code of the class
never mind my dumb question, I got it working, but I'm still getting unauthorized even though I use the token in the call
Check out my pinned comment, and sorry for the inconvenience!
@@MilanJovanovicTech no problem, I got everything working, fantastic video. Do you also have video's on how you set up a clean project from scratch?
Great video! Thank you so much!
This would have been even better if you had ditched Clean Architecture in favor of simple architecture; dare I say Minimal APIs?
Clean Arch forces you to create way too many files and abstractions to do a trivial task and I've got PTSD from it.
CA ain't too bad 😁 But thanks!
Nice video add it to playlist for watch when i will be need to implement Authentication
Done!
Do you have a video when you started this project from beginning ? I found you have already written a lot of codes. I am a newbie, and I found you have great contents.
Unfortunately, not. But the new series on eShop start more or less from scratch.
@@MilanJovanovicTech Okay, if you have a paid courses on User Authentication and Authorization pls share a link. Good work Milan
Hi Milan, following your technique to setup JwtBearerOptions through ConfigureOptions gives me a www-authenticate: Bearer error="invalid_token",error_description="The signature key was not found" error. I still need to add the configuration as a AddJwtBearer method parameter in order to get it working. It's a .NET 7 web api project.
Did you take a look at the pinned comment?
@@MilanJovanovicTech I missed the pinned comment. IConfigureNamedOptions did the job. Thanks.
Thank you, very useful. But, what should be changed to make it work on net core 6?
Just use the appropriate nuget package for .NET 6, everything else is the same
Great content! Is there a git repo for these videos?
Some of it I share on my GitHub, but if you want everything you can check out my Patreon page
Thanks Milan for your awesome video.
I hope you talk about how to Refresh JWT?
I'll consider it, didn't plan to. As I usually don't do any of this myself. I use an IDP
Can you please share a video link in which you written code for Application/Abstraction folder?
Not sure which one that would be
Awesome video! Correct me if I'm wrong, wouldn't it be a good idea to create an extension method for the Services? ex: builder.Services.ConfigureJwtSetup(), then the said ConfigureOptions will just be invoked there (well if those two are tightly coupled).
Of course, good idea. I didn't want to stress that topic here however
Hello! I encountered your videos on permission authorization and tried to return to the start of this 'series' link by link. This one seems to be the starting point, but, for example, throughout the video you use the Abstractions namespace from the solution. Am I right to assume that, for example, ICommand interface is your own written abstraction? Or is that some common logic that I'm just not familiar with? Being a little confused trying to follow along.
Feel free to grab the source code from the link in the description
@@MilanJovanovicTech ah thanks, somehow overlooked the link!
Hi, great video. I would just like to have one question. Why do you separate the login request and command? why doesn't the controller just take a command as a parameter?
Separating the public API from internal API
@MilanJovanovicTech thank you, are there some major security issues if you don't do so?
Correct me if im wrong...
The web tokens are stamped into http secure cookies, correct?
So the browser context which has the proper cookies has authorization, but the frontend doesnt have any way to indicate that it has auth cookies...right?
Are we conflating tokens and cookies? 🤔
Great tutorial. Can you also do one to explain refresh tokens.
Yes I can
Fantastic video! I'd love to see the using of the JWT expanded a little. For example yes they are a member and have successfully authenticated through the login endpoint. But they do not have permission to access GetMember endpoint based on claims (think it would be here that this differentiation would be set?). Would [Authorize] be un changed and the blocking of endpoint usage be within the endpoint method perhaps..
Anyway once again fantastic video had me captivated.
That's coming tomorrow 😁🔥
Hi Milan, great video. I am having a small issue implementing this though. I did not see in your video the adding of the service IJwtProvider to the program.cs. When I add these steps to my application I get a service issue on the JwtProvider. Any quick suggestions would be appreciated.
Add it as a Scoped service
Don't worry there were 2 issues. 1 was the IConfigureNamedOptions Implementation on the JwtBearerOptions and the service issue i resoled by just making the jwt token generation happen inside the authorisation controller and removed the JwtTokenProvider Class. All works now so thanks for the video. If you have a quick idea as to why the generate method works in the JwtTokenProvider class for you and not in my case it would be great to learn why.
@@chadjefferson8203 Did you check the pinned comment?
@@MilanJovanovicTech Yes thank that is how I figured out an error I was having with failed JWT signature. I did try the scoped service but was getting a life cycle determination error. Token Generation is cruelty working as part of the Auth Api so will leave it there for now. Thankyou
Thanks milan... Great video...
Glad you liked it!
Many thanks Milan, Can you extend it with OAuth 2 and OpenId-Connect.
Perhaps
Another great video, thanks 👍
Thanks!
Thank you very much for that! Can you say when should we use symmetric and when asymmetric keys to create JWTs? Currently we use symmetric, the server creates the JWT and sends it encrypted to the user. When the user sends it back, the server decrypts and checks it. The symmetric key is securely stored on the server. Do asymmetric keys have any advantages here?
Ideally, you won't implement any of this on your own. There are excellent third-party authentication services that implement this much more securely than what I showed in the video.
how to show data tip ( that looks same as browser JS debugger data tip ) like you without hovering mouse over variable?
I think it's ReSharper
Can you give me a video where you attach db first approch with db in clean artitecture?
Let me find it
Why is JwtProvider's interface in the application layer and not in the infrastructure layer along with its implementation class?
Because you need it in the command handler
@@MilanJovanovicTech Because the application layer cannot depend on the infrastructure, so calling the interface directly from the infrastructure would break the rule, right?
Excellent content! Thank again Milan.
Sure thing! :)
Hey! What extension are you using for the keyboard shortcuts (replacing words, autocomplete etc.)? It looks a lot like vim.
Thanks!
ReSharper
@@MilanJovanovicTech Thank you!
This video is so useful!
Thanks, glad you liked it!
Do you have a video on the ICommand pattern being used here?
Yeah, look for the CQRS video
hi @milan i liked ur way to do , but it not working at all . so i feel this is not full video or Code, do u mind share git repo for this.
I share it on my Patreon
Hi, Great content, i have this issue=> : Bearer error="invalid_token", error_description="The signature key was not found". How can i solve it ?
Please take a look at the pinned comment
@@MilanJovanovicTech Thank, you, i found my problems, issue with postman, after resolving my problems with postman, now works perfectly. Thank you for this content and for your answer.
What are your thoughts of storing refresh and access tokens in localstorage? I have implemented refresh token rotation, and I do store the tokens in localstorage. So if the request is 401 etc I send to token/refresh and get new token pair and continue with the original request. But I am reading a lot of mixed information, some say its considerably more safe to store it in httponly cookies.
I would appreciate your input on the implementation. Its a system where users login with a personal id. So its a bit sensitive, maybe httponly cookies is better then?
I'm not a UI expert 🤷♂️ But I did in the past, don't tell though...
So I'd refer to someone who does Frontend work for a living 😁
@@MilanJovanovicTech Okay, thank you :D I will go for the implementation I have right now but will consider switching before deploying.
Appreciate the answer :)
@@sonnyskold5634 Hi! Since the refresh request will inherently always need the refresh token (and the refresh token will need to be sent to the UI in the first place), there really isn't a way to keep it safe from bad actors; as is generally the case with anything on the frontend. If you want it safe, keep it server side. The safety in these tokens comes from the hashing. It's actually pretty neat if you look up how it works, basically all the parts of everything that's encoded get meshed together and most stay on the server so the client knows very little about from what the token is generated.
In terms of how to handle it, it depends on the concerns of the application.
You'll often see websites have a "User inactive, you will be signed out in 'x' seconds, click to refresh" popup. I'm not certain but I assume that's just doing the refresh haha. Regardless if you're doing automatic token refresh, you should really do something to have either your users opt in or let them know that's what is going on for ethical considerations.
You do want to make sure you're rotating your refresh tokens. You don't want any to be long-lasting.
That said, what you listed works fine haha. I've done that in plenty of personal projects. For something more professional you should really do the pop-up.
I just looked at Jwt authentication and was wondering: I wanted to use this for authentication API users where I supply an 'apikey' in the form of a Jwt. But then I want users to be able to use this token a long time (it will be configured in some backend services), but still have the ability to revoke it when needed. Am I correct in thinking the only way a Jwt can be revoked is by changing the Secret that is used to validate tokens, or I should store the token in the Api to have a revocationlist of tokens that I don't want to be used anymore.
Maybe this is not what Jwt was intended for but with an API service you would like to give users access, be able to change what access they have (which endpoints they can call) and also either extend or revoke their access. This is not something a Jwt does out of the box unless you program around this.
I tend to see a Jwt as something you can use to give shortlived access (hence the expiration) and during that time give access to a fixed set of resources, the claims (roles/policies) in the Jwt. It's handy that any endpoint can validate the token and give access to resources based on the claims inside this token without the need to go to some backend database.
In my case we have an API that has several endpoints, let's say Company, Contact, Order and some users might not have access to Order so the Claims could quikly block users there. But then a user might have access to Company A, and **not** Company B, thats access information that cannot be stored in the Jwt and has to live elsewhere...right?
But then when I have to store data elsewhere anyway, why not store as much of it elsewhere instead of in the Jwt...**I'm thinking of the Expire date here ** why store that in the token when I could also put in in the database, and even have the ability to extend it without having to give the user a new token.
@Milan Do you have some place to discuss this with others outside of the RUclips comments?
I don't have any community yet. I'm considering it though
@16:10 - you added app.UseAuthentication(); twice even though use said one should be app.UseAuthorization(); (lines 99 and 101) With that mistake, why did it work anyway?
Check the pinned comment
Hi, where can i find the source code? there is another series to develop this structure?
www.patreon.com/milanjovanovic
Why did you create 2 separate records, referring to LoginCommand and LoginRequest?
Splitting public contract from internal one
@@MilanJovanovicTech Thanks.
By the way, your source code is slightly different than the codes in the video. Did you make some improvements to it? For example, JwtBearerOptionsSetup is implemented IPostConfigureOptions instead of IConfigureOptions in the source code.
You should add a dependency injection for IJwtProvider
services.AddTransient();
It's in there somewhere
Hello! is there any chance to get the Source code?
Yes - on Patreon
Greate video, thank you. Do you have a video on how to configure a dotnet core webapi with EXTERNAL login providers, like Google, Facebook?
No, I don't and I'm not sure I'll make one with Google/Facebook soon
pretty good. bravo
Thank you very much :)
Great Video as always very informative! Q: Is there a way to invalidate a valid token, for example when the user changed password, or logs out?
That's a tough one, the short answer is no. But you can somehow store the token and check it on every authentication request, which is stupid and degrades performance. One option is to give tokens a short lifetime. Another option is to code your client side code to request a new token when a user does an action like that.
Hi Milan,
Is it ok if I added Authentication and JwtBearer in the Infrastructure project instead of UI?
Of course
A lot these videos and post of generating jwt tokens are out there but interestingly none on how to use the refresh token on a web client especially SSR client
Nothing magic about a refresh token. Create a token, store it in the DB. Client sends it to get an access token back.
hi,
If authorization fails and you get this error :
bearer error="invalid_token", error_description="the signature key was not found";
In JwtBearerOptionSetup class implement IPostConfigureOptions
Check pinned comment
30/07/2023 I tried it again and again but always get UnAuthorized! Are there any recent changes in .Net Core that affect it? Please help!
Check the pinned comment
Thank you. How can I download this source code ?
I share the source code on Patreon
Please make a series with Identity Server
I'll think about it
Great video
Thanks!
Milan, I get this exception whe try to create SymmetricSecurityKey: IDX10720: Unable to create KeyedHashAlgorithm for algorithm 'HS256', the key size must be greater than: '256' bits, key has '128' bits. (Parameter 'keyBytes'))
I believe the problem is somewhere in UTF8. Could you advise how to fix this?:
This you get the source code and try it?
BRIGHT SCREEN WARNING i LOVE IT
Saving your eyes 😂
How we download this Gatherly application? Please give any suggestions.
Check the description
Straight to the point Thanks Milan
Awesome
The video isn't complete, I can seems to get the issuer, Audience and the secret key values
How so?
Please, do video with refresh tokens.. Thank you!
Lets leave that to the IDP?
@@MilanJovanovicTech I'm a little uncomfortable, but I do not know what IDP is
@@DENDYTWOO No reason to be, I never discriminate on knowledge. 😁
IDP = IDentity Provider
What would that be?
- Identity Server
- Active Directory
- Auth0
- KeyCloak
- Firebase Authentication
@@MilanJovanovicTech I really appreciate you answering my question. I do not know what I should answer your question about IDP, but now I know what it means. You are smart and kind, thank you for the answer and for your videos
Thanks its very helpfull
Glad it was useful! :)
Hello, I believe I have followed this tutorial perfectly a number of times and have created a solution just for testing it, though I am always hitting the same issue. When testing in Postman, I am getting the following error in the `WWW-Authenticate` header: `Bearer error="invalid_token", error_description="The signature key was not found"` - do you have any ideas why this may be happening?
Yes, I do believe I mistakenly configured JwtBearerOptionsSetup to implement IConfigurOptions, and it should be IConfigureNamedOptions or IPostConfigureOptions.
Also, at around line 105 in Program.cs, I have UseAuthentication two times. Where one of those should be UseAuthorization
Can you confirm those fixes solved the problem? And I'll add a pinned comment with the resolution, for anyone else that runs into the issue
@@MilanJovanovicTech I just want to say how much I really appreciate you getting back to me and helping me!
@@MilanJovanovicTech Just to confirm, using the IConfigureNamedOptions did fix my issue. RUclips seems to be deleting a lot of my comments.
@@manofqwerty RUclips is weird like that sometimes. Thanks for letting me know, I'll pin the explanation for anyone else that runs into the same issue.
Very nice!
Thanks!
Using the options pattern within your startup configuration is an overuse of the pattern. This will get refactored into an extensions method where you simply pass configuration into a static method where the JwtBearer options can be configured. Also the OptionsSetup folder is not very useful or extensible for scaling the app. Instead I would add a Middleware folder in the Api project (Gatherly.App) then add folders as you create more startup extensions (Auth, HealthChecks, OpenApi, Telemetry, Validation, Etc.)
Makes sense
thanks ,
where is the code ? can you send the link
The source code is shared on Patreon
tnx for answer , but i can't access to patreon in my country ,tnx for sharing your information @@MilanJovanovicTech
May i somehow implement this to the .NET MVC project?
Why not?
You are implementing examples of a project. Where is the code for this project or any operating list in which the project was built
It's right there, if you look
Hi Milan,
what about if i take this token and called specefic function with parameter not allowed to me ? how i can prevent it to happen specially from postman interface.
Thanks
I didn't quite follow what you asked. Could you rephrase?
@@MilanJovanovicTech if you take the jwt token and make request from postman if will be accepted even if this api is acepefic for 1 user, what shall i can do to prevent this to happen?
i hope you can get what i means
in another way lets supposed there is api with email id to get all email info. anyone can use this api through postman with valid jwt token with random email id to get email info without he has the access to this email itself.
@@ramysamir1987 You need to add the concept of resource authorization to that. Based on the JWT you can know WHO the user is, and determine if they can access that specific email
can I watch this without having to watch the clean architecture and ddd series?
Yes
Doesn't work for me, I keep getting:
Bearer error="invalid_token", error_description="The signature key was not found"
Try using IPostConfiguteOptiond for the JwtOptionsSetup
@@MilanJovanovicTech i tried it out but it does not seem to work, after some debugging it looks like the JwtBearerOptionsSetup class does not run at all, seems that if i extend IConfigureNamedOptions instead of IConfigureOptions it works.
@@pseudocoffee4829 , Thanks for posting this. I was seeing a similar problem and hardcoded the config as a work around. I kept both interfaces and simply called the original Configure(options) from Configure(name, options).
Hi milan ❤
What is issuer and audience usage?
I think this sums it up nicely: www.quora.com/How-can-I-understand-audience-and-issuer-in-JWT-authentication