Overcoming Backend Challenges: My Journey with Flask and React Integration
As I embark on an exciting 8-week internship with the HNG Internship program, I reflect on a recent project that tested my skills and perseverance: NeighborShare. This web-based application, designed to facilitate resource sharing among neighbors, presented me with several challenges that ultimately helped me grow as a backend developer.
The Challenge: Integrating Flask-Login with React
One of the most significant hurdles I faced while building NeighborShare was integrating user authentication. Initially, I chose Flask-Login for managing user sessions. However, I quickly discovered that Flask-Login didn't play well with React. The primary issue was that Flask-Login relied heavily on server-side session management, which clashed with React's client-side rendering.
The Solution: Switching to Flask-JWT-Extended
To overcome this challenge, I decided to implement user authentication using Flask-JWT-Extended. This library allows for secure token-based authentication, making it a better fit for a React frontend. Here’s how I tackled the problem step-by-step:
Step 1: Setting Up Flask-JWT-Extended
First, I installed Flask-JWT-Extended and configured it in my Flask application. This involved adding the necessary imports and setting up the JWT manager:
from flask import Flask
from flask_jwt_extended import JWTManager
app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'your_jwt_secret_key'
jwt = JWTManager(app)
Step 2: Creating User Models and Routes
Next, I defined user models and created routes for user registration, login, and logout. I used SQLAlchemy for database interactions and md5 for password hashing.
from flask import request, jsonify
from hashlib import md5
from models import db
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity, get_jti
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
@app.route('/register', methods=['POST'])
def register():
data = request.get_json()
password_hash = md5(data['password'].encode('utf-8')).hexdiget()
new_user = User(username=data['username'], password=hashed_password)
db.session.add(new_user)
db.session.commit()
return jsonify(message="User registered successfully"), 201
Step 3: Implementing Login
For the login process, I created a route that checks the user's credentials, generates a JWT token upon successful authentication, and returns the token to the client.
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
user = User.query.filter_by(username=data['username']).first()
password_hash = md5(data['password'].encode('utf-8'))
if user and user.password == password_hash.hexdigest():
access_token = create_access_token(identity={'username': user.username})
return jsonify(access_token=access_token), 200
else:
return jsonify(message="Invalid credentials"), 401
Step 4: Implementing Logout with Token Blacklisting
To handle user logout securely, I implemented a token blacklisting system. This involved creating a table to store blacklisted tokens and modifying the logout route to add tokens to this blacklist.
from models import db
app.config['JWT_BLACKLIST_ENABLED'] = True
app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access']
class InvalidToken(db.Model):
__tablename__ = 'invalid_tokens'
jti = db.Column(db.String(36), nullable=False, index=True)
@classmethod
def is_valid(cls, jti):
"""checks if the token is blacklisted"""
return bool(cls.query.filter_by(jti=jti).first())
@jwt.token_in_blocklist_loader
def check_if_token_is_blacklisted(jwt_header, jwt_payload):
jti = jwt_payload['jti']
return InvalidToken.is_valid(jti)
@auth.route('/logout')
@jwt_required()
def logout():
jti = get_jwt()['jti']
user_token = InvalidToken(jti=jti)
db.session.add(user_token)
db.session.commit()
return jsonify(message="Successfully logged out"), 200
Step 5: Securing Endpoints with JWT
With user authentication in place, I secured protected routes using JWTs. This ensured that only authenticated users could access certain parts of the application.
@app.route('/protected', methods=['GET'])
@jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
The Outcome
Switching to Flask-JWT-Extended solved the authentication issue and allowed me to create a seamless experience for users. The JWT tokens facilitated secure communication between the backend and the React frontend, ensuring that user sessions were managed effectively. Implementing token blacklisting for logout further enhanced the security of the application.
The Journey Ahead
Starting my internship with the HNG Internship program is a thrilling opportunity to further develop my skills and tackle new challenges. The program offers a fantastic platform for learning and growth, and I’m eager to contribute to meaningful projects while honing my expertise in backend development.
Why HNG Internship?
The HNG Internship is renowned for its hands-on approach to learning and its supportive community. By participating in this program, I hope to gain invaluable experience, connect with like-minded individuals, and make a tangible impact in the tech world. If you’re interested in joining or hiring from the HNG Internship, check out their internship and hire pages for more information.
In conclusion, overcoming the challenges in NeighborShare was a significant milestone in my development journey. It taught me the importance of adaptability and problem-solving, skills that I am excited to bring to my internship experience. Stay tuned for more updates as I embark on this exciting path with HNG!
Subscribe to my newsletter
Read articles from Daniel Olaitan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by