0

I am trying to build an authentication application for the first time using flask and flask session for the backend and Nextjs for the frontend. Upon research I came across this article on medium link, which I followed carefully.

config.py

# Import the `load_dotenv` function from the `dotenv` library.
# This is used to load environment variables from a `.env` file.
from dotenv import load_dotenv

# Import the built-in `os` module, which provides functions to interact with the operating system.
# It is used here to access environment variables.
import os

# Import the `redis` library, which is a Python client for Redis.
# Redis is commonly used for caching, real-time analytics, and message queuing in web applications.
import redis

load_dotenv()

secret_key = os.getenv('DATABASE_SECRET_KEY')


class ApplicationConfig:
    SECRET_KEY = os.getenv('SECRET_KEY')
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = True
    SQLALCHEMY_DATABASE_URI = f'mysql+pymysql://root:{secret_key}@localhost:3306/user_register'

# Here we use Redis for server-side sessions to keep the authenticated session alive.

# Enable session configuration and set it to use Redis
SESSION_TYPE = "redis"

# Set session as not permanent, meaning sessions expire when the user logs out or after a certain period of inactivity
SESSION_PERMANENT = False

# Use a secret key signer for session data to enhance security
SESSION_USE_SIGNER = True

# Configure the path to the Redis server
SESSION_REDIS = redis.from_url("redis://127.0.0.1:6379")

app.py

from flask import Flask, request, jsonify, session

# This is used to load environment variables from a `.env` file.
from dotenv import load_dotenv

# Import the built-in `os` module, which provides functions to interact with the operating system.
# It is used here to access environment variables.
import os

# Import Bcrypt for password hashing
from flask_bcrypt import Bcrypt

from flask_sqlalchemy import SQLAlchemy

# Import Flask-Session for session management
from flask_session import Session

# Import Flask-CORS for Cross-Origin Resource Sharing
from flask_cors import CORS

# Import your application configuration from config.py
from config import ApplicationConfig

#create a flask application 
app = Flask(__name__)

# initialize application
app.config.from_object(ApplicationConfig)

#for pasword hashing
bcrypt = Bcrypt(app)

#set up the session
server_session = Session(app)

#for Cross-origin resource sharing
CORS(app, supports_credentials=True)

# Create an instance of the SQLAlchemy extension
db = SQLAlchemy(app)


with app.app_context():
  db.create_all()

  #Models

  #User model
class User(db.Model):
  __tablename__ = "users" #for table name
  id = db.Column( db.Integer, primary_key=True ) #assigns an id as a primary Key
  email = db.Column( db.String(180), unique = True ) #each email given has to be unique
  password = db.Column(db.String(255)) #limit bycrypt password hash 30

# Initialize the database
def initialize_database():
    with app.app_context():
        db.create_all()


#Register User route
@app.route("/api/register", methods=["POST"])
def register_user():
    # Get email and password input from the request body
    email = request.json["email"]
    password = request.json["password"]

    # Check if the user with the given email already exists
    user_exists = User.query.filter_by(email=email).first() is not None
    if user_exists:
        # Return an error response if the user already exists (HTTP status code 409 - Conflict)
        return jsonify({"error": "User already exists"}), 409
    
    # Hash the password using the Bcrypt library
    hashed_password = bcrypt.generate_password_hash(password)

    # Create a new User instance with the email and hashed password
    new_user = User(email=email, password=hashed_password)

    # Add the new user to the database session
    db.session.add(new_user)

    # Commit the changes to the database
    db.session.commit()

    # Set the user's session to keep them logged in
    session["user_id"] = new_user.id

    # Return a JSON response with the new user's ID and email
    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })
#Login route
@app.route("/api/login", methods=["POST"])
def login_user():
    email = request.json["email"]
    password = request.json["password"]

    # Query the database to find a user with the provided email
    user = User.query.filter_by(email=email).first()

    if user is None:
        # Return an error response if the user does not exist (HTTP status code 401 - Unauthorized)
        return jsonify({"error": "Unauthorized"}), 401

    # Check if the provided password matches the stored hashed password
    if not bcrypt.check_password_hash(user.password, password):
        # Return an error response if the password does not match (HTTP status code 401 - Unauthorized)
        return jsonify({"error": "Unauthorized"}), 401
    
    # Set the user's session to log them in
    session["user_id"] = user.id

    # Return a JSON response with the user's ID and email to indicate successful login
    return jsonify({
        "id": user.id,
        "email": user.email
    })

# Run the application
if __name__ == "__main__":
    initialize_database()
    app.run(debug=True, port=5555)

When I run the command at the terminal:

flask run

Since I have already set My flask app in the .env. The application works well. Upon testing the routes like the register and the login route I keep getting this error:

ERROR:

RuntimeError: The session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.

I really do know why because upon further research I had to set up the SECRET_KEY which I beleive I have already done in my config.py file.

Here is another thing in postman, the register route when I test it with some raw data it first shows the error and if I click it again it shows that it has been inserted into the database. But when I test the login route it doesnt work, it get stucked at the same error.

Please what is missing?

1 Answer 1

0

So after getting the error persistently, I decided to start over again and then encountering the same error, but this time I found out that I was missing two necessary steps.

#Step 1: start the redis server I brewed install redis on my macos

brew install redis

Then started the server

brew services start redis

I also installed redis in the virtual environment of my application

pip install redis

#Step 2: add the session settings to the ApplicationConfig class in the config.py

import redis from decouple import config from dotenv import load_dotenv load_dotenv()

class ApplicationConfig:
    SECRET_KEY = config("SECRET_KEY", default="guess-me")
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = True
    SQLALCHEMY_DATABASE_URI = config("DATABASE_URI", 
    default=r"sqlite:///db_name.db")
    #enable session config
    SESSION_TYPE = "redis"
    #so that session won't be permenant
    SESSION_PERMANENT = False
    #use secret key signer
    SESSION_USE_SIGNER = True
    #set the path
    SESSION_REDIS = redis.from_url("redis://127.0.0.1:6379")

After making this modifications to the code. I tested the register and the login url in postman and the error didnt come up again.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.