FastAPI Authentication with JWT (JSON Web Tokens)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey guys what's up hope you're all doing great recently i've received many requests that i continue creating more tutorials on fast api framework especially after the good reviews of the farmstack course and fast api crash course videos there was three particular requests to demonstrate how to authenticate users in a fast api application only authenticated users will be granted access and control over the usual verbs in any other application get post put and delete only in this application we'll be demonstrating on the post verb only so this is what we're going to be doing today with fast api and json web tokens or jot for short just before we get started i would like to thank all the new subscribers to the channel feel free to reach out in case of any question or if you need me to help you with your school or university projects i do my best to create high quality tutorials to help you better understand different sides of different technologies so if you feel like supporting us you can do so by just subscribing like the video and ask me any questions in the comments and you can also share these videos with your friends and colleagues that would really mean a lot to me now with that out of the way let's stroll up our sleeves and get started so let's talk for a minute about authentication authentication is the process of verifying users before granting them access to secured resources and when a user is authenticated they're allowed to access these secured resources which are naturally not publicly shared we will be looking at authenticating a fast api application with token based authentication which involves generating security tokens they are called bearer tokens or holder tokens because you the user who want to be authenticated you are the holder of that token of that security key that will prove that you should be authorized to these secured resources and the better tokens in this case will be the jots or the json web tokens and by the way i have a flask jaw tutorial demonstrating the same thing but as you see nowadays the hype for fast api is real and developers are switching from flask to fast api for a lot of reasons like super speed for instance and you can take a look here to the tekkenpower.com website you will find different statistics about the speed the latency here for example we have responses per second at 20 queries per request and you can see on the screen that fast api is number 11 with 12 774 responses per second at 20 queries per request and this is a very high performance very high score you can see here higher is better starlet comes next uv core number 17 pyramid is 36 tornado 41 flask 42 so you see the difference between flask and fast api 12774 responses versus 1773 responses and this is in general a performance comparison executing fundamental tasks like json serialization database access server-side template composition and each framework here is operating in a realistic production configuration so the bottom line here is fast api is really fast and this is one of the main reasons that a lot of developers are switching from flask to fast api not only speed but also performance ease of syntax you have something like pedantic that allows modern python typing you have asynchronous requests with async await syntax so you see the advantages of using fast api are huge and time and effort efficient for you as a developer alright so i'm going to create the folder now i'll call it fast api dash app and let's see that and let's open that folder with visual studio code alright so you see i have an empty folder called fast api dash app and let's actually activate the virtual environment i'm using ppnv so now i'm going to activate the virtual environment by typing ppnv shell all right perfect let's create together uh requirements.txt we are going to include in that file our dependencies we need for now fast api and uv corner server so the fast api version is 0.70.0 and also i need uv corn 0.15 0.0 save that and ctrl l to clear the terminal ppnv install dash r requirements.txt so fast api does not have a built-in development server like the g-unicorn which is a whiskey server in flask for instance so we're using uv corn here which is an ascii server so ascii stands for asynchronous gateway interface and whiskey which is in flask is a web server gateway interface so the uv core server here we're using in fast api this has one role is to serve up fast api so this will actually connect the server to our application but it's way way faster than whiskey in flask all right perfect let's go ahead here and create one folder call it app and inside app i'm going to create another folder i will call it auth for our shot authentication functionalities and also inside app i'm going to have model dot py and then in the main fast api dash app i'm going to have a main.pi file so let's just close that first and let's create main.pipe so main.pi is going to be our main entry point for running the application okay so first of all let's go ahead and import uv corn and also i want to import from fast api i want to get fast oops fast api and i'm going to instantiate a fast api application app equal to fast api not this one fast api and now we have our main application which is an instance of the fast api class okay and below here i'm going to create a decreator for my main application with a get drought and this is going to be the home page and tags we're going to give it tags or group let's actually call it tests this is actually a test for the get request so creating a function called greet going to return hello world all right now to run the fast api app you will need to use the uv corn server here so uvicorn main which is our main file which is called main.pi column app and this means that the main file is mapped toward the app application or the instance of that fast api class then dash dash load and reload is the same like the debug mode in flask okay you don't have to restart the server each time you want to make modification and this dash dash load helps you to update or modify your web page without interrupting the server without disconnecting and then connecting and then refreshing the page instead you can hit refresh and the modifications will be applied immediately okay so let's hit enter all right perfect so it's running on the localhost port 8000 let's click on that link and we have our hello world okay and if we will go to docs you'll have here the test which is the tags that we have defined we have our get request with the method of greet if you will click on try it out execute you will have a successful response hello world and if you will take that curl link you will copy it and if you have git bash installed on your system you can just enter this on your terminal or if you're running on linux or mac it has curl already installed in the in your bash terminal so you don't have to install anything but for windows you will need get bash installed and hit enter and you will get a successful response hello world all right so now we we are sure that everything is working okay initially and our application is well instantiated all right just before we move on let's go ahead and import pedantic in model.pi so from pedantic i want to import base model base model field and an email validator which is the email store and let's go ahead and create a class and this class for posting and this is actually for the post schema so post schema it will take the base model so we will need different fields we will need an id we'll need a title and we will need the content so this is going to be a blog post actually so there will be a schema for the post and the schema for the user so first we are starting by the post schema and after we're going to create the user schema so the id is actually an of type integer and it's going to be equal to field and i'll give it default to none and i need two more here i need title and the title is stir of type stir field also i will leave it i will leave the default to none this is base model not maze model also we need the content and i want to give an extra schema for the configuration so how the post is going to be formatted so here below let's create another subclass and i'm going to call it config so the schema extra is equal to an object or a dictionary and uh the first or the only key here it's a key value pair so the first key is post demo i'm going to call it post demo and it has a value of two key value pairs a title and a content we won't include the id because it's auto increment so i don't need to put it manually so the title say here some title about animals and the content some content about animals so that's what the format of the post should look like okay in the main.pi file we will need to import the post schema so let me just show you the whole map so from app.model i want to import um the post schema okay the post schema class will need it here and let me just create dummy posts so we're not going to wire up with any database it's just dummy data here for posts but you can go ahead and raise the bar and try to connect that at the end of the tutorial of course after you have seen everything you can try to connect this with mongodb or postgresql for data persistence okay so posts is a list actually and the first post here so um id here is one as an integer title penguins and some text about penguins i'm also going to add two more posts all right now we have three posts penguins tigers and koalas and also i want users list which is going to be empty for now and we're going to append the users to the users list later now let's go ahead and add more routes so we are going to add get all posts and get a post by id get an individual post by id so here let's just add a comment here this is get not get post just get for testing it doesn't have to do anything we can delete it actually uh just i will leave it for now uh here get posts and also we want get post by id get single post by id okay that's better okay so also let's just give them numbers one two and three okay so this is very easy we want our appdecorator to get all posts and now the tags we are going to give it a name of posts and we're going to define a function we're going to give it a name of get posts and we're simply going to return the posts so return and you can say data we are going to return all the posts which is our main list here so this is to get all posts and if i want to get one post only we want to just target by a specific id so get and in the route we will need to go to posts route and then an additional route for the id then also in the tags of posts so def get we are going to call it get in get one post get one posts um and also here i want to specify that the id is of a type integer and here i want to check if the id that i'm entering is bigger than the length of the posts if this is true i want to enter or i want to return an error message actually so we are going to return error post with this id does not exist and then we want to loop over posts so for post in posts i want to check if the id of that post so if post sub id is equal to whatever id i'm entering which will be in the parameter in in the argument here in the main input if this is true let's go ahead and return that post so return post all right let's just go ahead and try that but first let's trap this the tags let's trap what's inside the list in double quotes okay save and let's get back to our page okay good so we have both posts i mean posts tags we have get posts and get post by id okay so get posts if you try it now execute we're going to fetch everything from our list okay so data id 1 title text id2 title text id3 title and content i don't know why uh just mistake here is texts okay so not big deal let's just try with one post by id so get one post and let's click try it out and if we want the third id execute and we get the id3 of the koalas okay pretty cool and if you will take that copy and paste in your bash terminal hit enter and you will get the same result okay cool now let's go ahead and work on our posts method or posts request so let's just add here number four uh post a single blog post without single because naturally it's a single blog post so or for more explanation handler for creating a post okay so again we need our the creator app.uh not get post and we're going to post on the same route slash posts and the tags naturally is going to be posts and let's create our function uh we'll call it add post and the post here in the parameter is going to be called or mapped from the post schema you remember from our mongol.pi okay that we have imported here and here we want to continue adding posts so post zero so zero plus one is going to be equal one one plus one equal two two plus one equal three and so on so post dot id is equal to the length of the posts which is currently three and we're going to increment it by one also we're going to append each post to the posts list so posts dot append and inside here post dot dictionary because each post is of a type dictionary and we will return info post added all right now let's go ahead to our page and refresh again and we should see the post request or the post route if we will try it out we will say here title let's say cats and let's type cats are cute okay execute and we have here status code 200 which means successful response info post added and you remember when i spoke about uv core there it is server is uv core okay and let's if we'll take this we'll copy that again we will go to our bash terminal hit enter info post added so it should be added two times one time we did it from the open api from the swagger and the second time we did it from curl so if you will go ahead and get posts try it out execute we should see two times there it is alright so before we move on let's go ahead and create the json web tokens token handler we're going also to create a class to handle the bearer tokens so before beginning we will need to install the pi jot package and the pi job package is used to encode and decode the jots or the json web tokens we're going also to use the python decouple dependency or package and this is used for reading the environment variables now let's go ahead and vpnv install requirements.txt in order to add both packages the pie chart and the python decouple in the meantime we'll go to the auth folder and i want to create jot underscore handler dot pi and the jot handler file is going to be responsible for signing for encoding decoding and returning the tokens so let's just add a comment here this file is responsible [Applause] so until the installation of the dependencies is finished let's go ahead and import time and the time module will be responsible for setting an expiration limit for the tokens because every jot or every token has an expiry date or expiry time where it becomes invalid at some point all right the installation is finished the next package that we want to import is jot and the jot module is responsible for encoding and decoding generated token strings and the third package is from the couple we will import config and the couple helps you to organize your settings so that you can change parameters without having to redeploy your application it also makes it easy for you to store parameters in an ini or env files so this is what we're going to do now so here in the base directory go ahead and create dot env file and in that dot env file we'll need two things a secret which will be a secret key and the jot algorithm and i'm going to show you on the website right now but first let's have a secret and in python there are a million ways to generate a random secret key but i prefer personally let me just show you very quickly so go to your python interpreter and import a package called import a package called secrets okay it's a built-in package you don't have to install it then use that package secrets dot token underscore hex and you enter the number of the characters that you want python randomly to generate it so let's say 16 characters for instance enter and you will have a random character if you want more you can type 20. you can get more if you want less you can get less i'm going to use the 16 characters tokens hex here and i'm going to paste that and the second variable is the algorithm and the algorithm is going to be h hs256 all right good now let's close the dot env file and let's get back to our jot handler file what i want to do now is i want to create two variables one will be the jot secret and another for the jot algorithm okay will be um like pointing towards the secret and the algorithm in the env file so dot secret is equal to config secret oops and jot algorithm all right so the secret key is used for encoding and decoding jot strings and the algorithm value is the type of the algorithm used in the encoding process which is as we said hs 256 now i want to create a function which basically will return the token so i'm going to call it token underscore response and it's going to take the token with the type of string and it will return and here we'll say access token and we will return that token or we'll display that token here and now what happens that these json web tokens are encoded into strings from a dictionary payload all right so this function returns generated tokens let me just minimize that a little bit let's close this and let's actually close that for now we don't need it the next function that i want to create is a function that will use to sign the jot string so the payload for this sign jot so let me just create the first sign jot and we'll need the user id okay and this is going to be of type string we have a payload which will essentially be equal to a dictionary composed of a user id and expiry or expiration time so first of all we have the user id which is passed in the parameter above in the sign job function and this is a map toward the user id and the value for that key is the user id passed and also we want expiry or expiration date or time and the expiry is being set to time that's why we have imported the time module above so time dot time and we are going to add let's say um 1 200 milliseconds but that's not all because we want the token now and the token is going to be equal to the jot package dot in code we're going to encode everything inside that method so first of all we need the payload next we want the key or our secret key that we have defined in the dot env file last but not least is the algorithm which is equal to our jot underscore algorithm okay so these are the three main things that we'll need to encode using the jot and all of that is going to be stored in a variable called token so we want to pass all of that as an input in the token response let me just add one comment here good the last function in our jot handler.pi will be the decode jot and the decode jot function will take the token and decodes it with the aid of the jot module let me just show you that very quickly so let's go ahead and create that decode jot function and the decode jot function also will take that token of type of string and we want to decode that token so go ahead and create a new variable called the code token which will be equal to that jot package dot decode method and inside the decode method we're going to pass the token we also need the key which is the jot secret and also the algorithm is pointing towards the jot algorithm so what happens here is that this function takes the token and decodes it with the 8 of the jot module and then it stores all of that in the decode underscore token variable and then we want to return the decode token if the expiration date is still valid okay so if the code underscore token expires here is more than or equal to the current time else we're going to return none and let's actually wrap all of that in a try accept block and here we will return whatever will be returned so again this is actually a function that takes the token and decodes it uh with that jot module and then it stores it in the decode token and we're going to return it unless the expiration time is over just one very important note that the token itself is not encrypted it's a base64 representing binary data to put it simply just this is binary to text zeros and ones encoded to plain text and signed okay so anyone can decode the token and use the data but only the server here on the jot website can verify its authenticity using the jot secret all right perfect now let's go ahead to the model.pie and we want to add more schemas for handling the registration and the login so i'm creating a user schema now user schema base model and i need the full name of type of stir and this is equal to field and let's the default make it equal to none also email of type of email stir which we have imported above and email stir is an email validator so later we will need to install an email validator package from pedantic and this is also the field default equal to none and password of type of string and this is equal to again i know this is boring uh or just bear with me we're almost there default equal to none also let's have a class for the configuration just for the format so we'll call that this schema and the schema here will have um let's call that user demo and we'll have a name back email okay so this is the general schema for the user also i need the user login let's actually copy that so instead of the user schema it's going to be the user login schema and i don't need the full name because in order to log in we need only the email and the password okay and user demo that's fine and here we don't need the name we need only the email and the password good now let's go to our main file and we're going to import the schemas and also the jot sign function from the jot handler file that we have created so let's go to main and let's go here above and we're going to import from app dot model we want to import post schema we want to import user schema and user login schema i also want to import from from app dot auth dot jot handler i want to import and it was called the sign jot need that for signing all right let's just go and check out what we have so far let's just close that and um uv corn main app dash dash load and let's go directly to docs um something wrong okay oh okay um we did not install that for the email validator um i told you that we want to install the email validator uh from pedantic but we didn't do it okay so let's do that actually quickly ppmv install pedantic email all right perfect just run the server in the background um okay and just close this one okay we don't have any errors um i won't use anything now because we will need to create the the sign up and the login routes i just i will leave it here in the background and let's go ahead now and create these routes so the fifth route actually is going to be for user sign up create a new user so we're going to create a new tags so let's have our app the creator dot posts and we're going to have the user route slash sign up and here we will have our user tags and let's create a function called user sign up so this is for new users and the user is pointing to the user schema if you remember that we have created and imported from the model.pi all right and what i want to do is to append each new user to the users list so users dot append each user okay let me just add the default to be equal to none and by the way i will need to add buddy from fast api import fast api and body all right and then we want to invoke the sign jot method okay so we will return that actually sign dot passing inside the user's email user dot email and that's why we had to install the email validator from pedantic next we want to define a function this function will check if a user already exists before creating a jot with the user's email so this is just a function to check the and user data here will be pointing to the user login schema and if you remember in the model.pi the user login schema had the email and the password so here what we want to do actually is to iterate through the users so for user in users we want to check if user.email is equal to data.email and user.password is equal to data.password if all of that is true then we want to return true else we will return false all right perfect let's go ahead and check out our open api all right so we have here our user sign up take a look here perfect we have the schema and if you will try it out actually nothing will happen but just the value will change let's say for instance hello and we'll get an error because we didn't create our login yet but if you will clear that and if you will say cancel you see that everything has been changed here all right so let's reset that and let's get back to our code now it's time to create our login route and also here by the way should be a slash like that forward slash the same thing goes here user login and the tags is also going to be user and let's create a function we will call it here user signup let's make it user login and i want to map the user instead of the user schema here the user login schema user login schema okay and also the buddy we want to return sign jot with the user email because he has already signed up and registered with his email else we will say that the information that you have entered whether the email or the password are invalid so we want to take our check user function and we're going to pass in here the user and we will return sign jot sign jot method with user.email else we will return a message that says that invalid login details simple as that return oops i forgot the default default equal to none all right let's save that all good all good okay let's get back to our swagger ui and check this out user sign up and user login so user sign up let's actually try to sign up full name let's say um john john string let's say hello one two three okay execute okay we have a server error um algor oh okay in jot handler here algorithm okay all good let's try that out one more time let's execute and there you go this is our jot okay and if you will uh scroll below here and you try to log in let's actually try to log in with any other user that has not signed up so let's say for instance then and any password let's keep it string execute will have invalid login details if we will enter our email correctly i'll say hello one two three execute and we will get also our token so the last step here is securing the routes as i said we need to verify the protected route so we're going to do that by checking whether the request is authorized or not so we're going to scan the request for the token in the authorization header and fast api provides actually basic validation via something called http bearer class we're going to use the http bearer class in order to extract and parse the token all right so let's go ahead to our auth folder and create jot underscore bearer dot pi so the objective of this file is to check out if the request is authorized or not so i want to import a bunch of dependencies here so from fast api i will import requests and http exception and also i want to import from fast api dot security i want to import the http bearer we also need http authorization credentials and let me just create a class and we'll call it jot bearer and this will take http bearer class as the main parameter or the main argument so this jotbearer class is a subclass of the fast api's http bearer class this will be used to persist authentication on the routes so the jotbearer class is a subclass of the fast api's http bearer class and let's have init method and it has self as the first argument next auto underscore error of type boolean and we'll set it to true and super method takes the jot bearer class and here the job bearer class has the http bearer super class okay so we're going to inherit everything from the http bearer class and the second parameter is self dot init and auto error we're going to set it to auto underscore error like that which is passed here in the in that method okay which is upset to true basically next we will need to define a call method because we'll need the credentials of the bearer of the token so um here i'm going to use a sync before the keyword def to define the function so um and i explained a sync await many times in different videos in the tornado framework i have a separate video called async io but just to put it simply your computers or sources are being freed from the process and they go to do something else until that slow process is finished and then the resources are back and continue process and it's mainly io processes not cpu intense processes let's take self as first parameter then we want to set the request to the request class and what i want to do now is to create a variable called credentials and the credentials i'm going to set it to http authorization credentials and this equal to a weight now we are going to await or wait for that long process and that long process simply is the jot bearer class or that class that we're creating actually the self is going to call on that request that we have passed so this is the slow process let's just close that so we want to check if credentials then uh if credentials is true we want to check further so if not credentials dot scheme and the scheme here is equal to bearer so in other words if the credential scheme isn't a bearer scheme what we want to do we want to raise an exception that's why we have imported the http exception method class here this is a class so what i want to do is to raise http exception oops http exception and the status code status code is equal to 403 and the details or the info that i want to give to the user or in the open api i mean we want to write invalid or expire token else we want to return credentials dot credentials so if credentials is false for any reason we also want to have this http exception just i will copy it we'll paste it here the same exception the same status code 403 so the last function that i want to create in that job bearer class is a verification step for the jot so i'm going to call this verify underscore dot and this function will essentially verify whether a token is valid or not that's all that's all what it does so it takes self as first parameter and jot token which will be of type string and here i want to ask is token valid of type bool and we're going to set this to false so i'm creating here a variable called is token valid of type boolean and we'll set it to false as a flag so actually this is a false flag and i'm going to check out if the payload is true then istoke invalid is going also to be true so i will need to import here the decode jot function from the jot handler so i'm going to take this to import it in the job bearer so from dot dot handler import decode jot and i'm going to use that here below so i'm creating a variable called payload and i will take the decode dot function so we're actually going to decode whatever the j token or the gw token is being passed here okay and i want to check out if payload is true then is token is equal to true and at the end i want to return is token valid to post any blog post i will need to depend upon the jot or the decode jot function no one can just post like that only the signed up and log logged in users will be authenticated using the jot in order to post any blog post so to do that i will need to import a dependency called depends actually um interestingly enough it's called dependency and this depends package or depends dependency is being imported from fast api um also i will need to import from app dot auth dot jot bearer i want to import the jots bearer class i will need now to add dependencies as an additional argument and we're going to take depends and we are going to pass the jot bearer class okay and we'll add a comma like that so in post nothing will change just we will add the dependency of the jotbearer class make sure that the server is still running we will refresh and let's take a final look to what we have so first of all take a look to that green button authorize so this is new this was created after we have added the jot bearer class and we have added dependencies for the post so take a look here for posts you see that log so this is actually the authentication that would be necessary in order to post any blog post so let's take a look to all the routes now to get the posts or to retrieve the posts just you will click get post and everything is the same for get posts all right um if i want to have one post by id let's just try that out let's try the second post execute and we have our second post for tiger so there is no actually authentication for getting posts the authentication is only on posting any post so let's try to post a post post a blog post without creating a blog post without authentication title let's say monkeys monkeys are fun and if you will execute that you will get an error message detail not authenticated right so to solve that problem we need to be logged in and in order to log in we'll need to sign up first so let's go ahead and sign up try it out full name back info at back brace dot com password hello one two three okay execute and we receive a token now let's go ahead and close that let's close the user sign up and open the user login and let's try it out and we will log in using our email so back or info at backbrace.com password hello one two three execute and we get our token so we're going to copy that token ctrl c or just click here on the clipboard and you can get authentication by either clicking on the green button authorized or on clicking on that lock so if you will click here and let's paste our jot click authorize and we are authorized cool let's close that and now you can see here that the lock has been changed and now you are authorized if you will try to uh if you will try to post that blog post one more time execute you will get here info post added perfect let's check out in our get posts execute and we have our fourth post monkeys monkeys are fun alright so it's time to wrap it up thank you very much guys i hope you enjoyed this video if you have any questions please let me know in the comments and if you have any suggestions for future videos also please let me know in the comments below so until next time stay safe and be well take it easy guys
Info
Channel: Bek Brace
Views: 55,781
Rating: undefined out of 5
Keywords:
Id: 0_seNFCtglk
Channel Id: undefined
Length: 56min 17sec (3377 seconds)
Published: Fri Nov 05 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.