Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for JWT Auth in Flask Python
Graham Morby
Graham Morby

Posted on • Edited on

     

JWT Auth in Flask Python

Ever wondered how you use auth in Flask and secure some endpoints? Well, it's not that crazy, and it's pretty easy to implement.

So let's first start by creating a new folder - /JWTExample

Pop open a terminal and cd into that folder from your location and run the following command to set up a virtual environment.

python -m venv env
Enter fullscreen modeExit fullscreen mode

Ok before we carry on if you have python three installed you will need to use 'python3' and 'pip3' in your commands, if not its just 'python' and 'pip'.

Now we have our virtual environment squared away we need to grab some packages from pip to allow for what we need to do. Now this will be a very simple set up and you can go a lot deeper into flask auth.

Lets make sure we are in our virtual environment by running the following:

source env/bin/activate
Enter fullscreen modeExit fullscreen mode

So lets install:

pip3 install flask flask_jwt_extended flask_sqlalchemy
Enter fullscreen modeExit fullscreen mode

Ok so we have what we need to get started! PERFECT!

Lets first create a basic Flask app and make sure thats working all ok. So create a file called app.py and lets add the following code.

fromflaskimportFlask,jsonify,requestapp=Flask(__name__)# Planet Routes@app.route('/',methods=['GET'])defindex():returnjsonify(message='Welcome to flask!')if__name__=='__main__':app.run()
Enter fullscreen modeExit fullscreen mode

If we then useflask

run

we should be greeted with our wonderful message of 'Welcome to Flask'.

So we have done the first step, lets push onto the next. So the next step is allowing a user to create an account. Now for this tutorial we are going to use SQLite as a database but you can of course use any one of your favorites.

Ok so this next bit is a bit long but hang in there and it won't take long.

So first we need a package called marshmallow

pip3 install flask-marshmallow
Enter fullscreen modeExit fullscreen mode

Let make sure that is being used

fromflask_marshmallowimportMarshmallowfromflask_sqlalchemyimportSQLAlchemyfromsqlalchemyimportColumn,Integer,String,Floatdb=SQLAlchemy(app)ma=Marshmallow(app)
Enter fullscreen modeExit fullscreen mode

Next, we need to add some flask CLI commands - these we can use to help users create the database and seed it with some data.

# DB set up and seeders@app.cli.command('db_create')defdb_create():db.create_all()print('Database created')@app.cli.command('db_drop')defdb_drop():db.drop_all()print('Database dropped')@app.cli.command('db_seed')defdb_seed():test_user=User(first_name='Stephen',last_name='Hawking',email='admin@admin.com',password='admin')db.session.add(test_user)db.session.commit()print('Database seeded')
Enter fullscreen modeExit fullscreen mode

Then we create a User database model, this tells SQL alchemy how to layout our Users table and what type of columns should be.

# Database modelsclassUser(db.Model):__tablename__='users'id=Column(Integer,primary_key=True)first_name=Column(String)last_name=Column(String)email=Column(String,unique=True)password=Column(String)# DB SchemasclassUserSchema(ma.Schema):classMeta:fields=('id','first_name','last_name','email','password')
Enter fullscreen modeExit fullscreen mode

and finally lets add the database connection strings

importosbasedir=os.path.abspath(os.path.dirname(__file__))app.config['SQLALCHEMY_DATABASE_URI']='sqlite:///'+os.path.join(basedir,'jwt.db')
Enter fullscreen modeExit fullscreen mode

Ok, so what is flask marshmallow? I guess the best way to describe it is it allows us to output our data in views in a neat way.

Wow, that was a lot of code! Well done you! If you pop down into the terminal and writeflask

db_create

you should see a message 'database created'!

Then we test the database withflask

db_seed

that will place our test data in the database and we are ready to look at the register endpoint.

So we need to create a registered route and save any new user to the database.

@app.route('/register',methods=['POST'])defregister():email=request.form['email']test=User.query.filter_by(email=email).first()iftest:returnjsonify(message='That email already exists'),409else:first_name=request.form['first_name']last_name=request.form['last_name']password=request.form['password']user=User(first_name=first_name,last_name=last_name,email=email,password=password)db.session.add(user)db.session.commit()returnjsonify(message='User created successfully'),201
Enter fullscreen modeExit fullscreen mode

Ok so a lot is going here, firstly we take some form data and check if that email already exists, then if it does we return a JSON object with a message stating an error. If we don't have that email we build a User object from all the form data sent in and then save it to the database. Then we return a JSON object with a 201 status and a message.

And now finally we are ready to install flask JWT! So let's grab the package and go for it

pip3 install flask-jwt-extended
Enter fullscreen modeExit fullscreen mode

So we have our JWT package and now we need to use it. This is a three ponged attack:

  1. Import the package
  2. Set up a super secret key
  3. Create an instance

So import as follows:

fromflask_jwt_extendedimportJWTManager,jwt_required,create_access_token
Enter fullscreen modeExit fullscreen mode

Set up a super secret key (Don't tell anyone!):

app.config['JWT_SECRET_KEY']='super-secret'# Change on production
Enter fullscreen modeExit fullscreen mode

Create an instance:

jwt=JWTManager(app)
Enter fullscreen modeExit fullscreen mode

So we are fully set up to use out JWT package, so now we build the login route.

@app.route('/login',methods=['POST'])deflogin():ifrequest.is_json:email=request.json['email']password=request.json['password']else:email=request.form['email']password=request.form['password']test=User.query.filter_by(email=email,password=password).first()iftest:access_token=create_access_token(identity=email)returnjsonify(message='Login Successful',access_token=access_token)else:returnjsonify('Bad email or Password'),401
Enter fullscreen modeExit fullscreen mode

So again loads going on here! So lets start walking through the code. In this code we are accepting JSON or Form Data, we take our email and password and we assign it to variables. We then test to make sure they match and if they do we create a JWT token! and we return a message and the token itself! Woop!! We made it.

So how do we test it I hear you say! Well if we add @jwt-required to our index method it will require us to have a JWT token to access it

@app.route('/',methods=['GET'])@jwt_requireddefindex():returnjsonify(message='Welcome to flask!')
Enter fullscreen modeExit fullscreen mode

So lets do some testing

First let's load postman and try and access the home route, we should get an error message as follows:

Flask JWT error message

Ok so that works! Let's login and get a JWT token returned, now remember we have already seeded our database and can use that user to login with:

Flask JWT returns JWT token

And now we need to add our Bearer token to our auth section and if we hit go on our post method we will get our welcome message! And we have fully installed Flask JWT Auth!

Flask JWT in place and working

Here is the full code in full:

fromflaskimportFlask,jsonify,requestfromflask_sqlalchemyimportSQLAlchemyfromsqlalchemyimportColumn,Integer,String,Floatimportosfromflask_marshmallowimportMarshmallowfromflask_jwt_extendedimportJWTManager,jwt_required,create_access_tokenapp=Flask(__name__)basedir=os.path.abspath(os.path.dirname(__file__))app.config['SQLALCHEMY_DATABASE_URI']='sqlite:///'+os.path.join(basedir,'jwt.db')app.config['JWT_SECRET_KEY']='super-secret'# Change on productiondb=SQLAlchemy(app)ma=Marshmallow(app)jwt=JWTManager(app)# DB set up and seeders@app.cli.command('db_create')defdb_create():db.create_all()print('Database created')@app.cli.command('db_drop')defdb_drop():db.drop_all()print('Database dropped')@app.cli.command('db_seed')defdb_seed():test_user=User(first_name='Stephen',last_name='Hawking',email='admin@admin.com',password='admin')db.session.add(test_user)db.session.commit()print('Database seeded')# Planet Routes@app.route('/',methods=['GET'])@jwt_required()defindex():returnjsonify(message="Hello Flask!")# User routes@app.route('/register',methods=['POST'])defregister():email=request.form['email']test=User.query.filter_by(email=email).first()iftest:returnjsonify(message='That email already exists'),409else:first_name=request.form['first_name']last_name=request.form['last_name']password=request.form['password']user=User(first_name=first_name,last_name=last_name,email=email,password=password)db.session.add(user)db.session.commit()returnjsonify(message='User created successfully'),201@app.route('/login',methods=['POST'])deflogin():ifrequest.is_json:email=request.json['email']password=request.json['password']else:email=request.form['email']password=request.form['password']test=User.query.filter_by(email=email,password=password).first()iftest:access_token=create_access_token(identity=email)returnjsonify(message='Login Successful',access_token=access_token)else:returnjsonify('Bad email or Password'),401# Database modelsclassUser(db.Model):__tablename__='users'id=Column(Integer,primary_key=True)first_name=Column(String)last_name=Column(String)email=Column(String,unique=True)password=Column(String)# DB SchemasclassUserSchema(ma.Schema):classMeta:fields=('id','first_name','last_name','email','password')# Marsh mellow db addsuser_schema=UserSchema()users_schema=UserSchema(many=True)if__name__=='__main__':app.run()
Enter fullscreen modeExit fullscreen mode

If you need to you can clone the code herehttps://github.com/GrahamMorbyDev/jwt-flask

That was alot to take in but now you can make some super secure API's and make some awesome code! Well done you!

JWT with Python

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Hey guys, 15-year developer! I code with Vue.js and Python, I love to learn but also love to teach! So I try and write informative tutorials and posts. I am new to blogging and would love any feedback
  • Location
    Portsmouth UK
  • Work
    Senior Developer Leighton
  • Joined

More fromGraham Morby

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp