skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    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.


  2. From what you shared it seems you are missing .env file!
    Create a file called .env at the root directory of flask project.
    in that file put this:

    SECRET_KEY=your_secret_key_here
    

    replace "your_secret_key_here" with a proper secret.

    in order to debug your code, put this line at the config.py to see if the secret is correctly set or not:

    print(f"SECRET_KEY: {ApplicationConfig.SECRET_KEY}")
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search