Integrating PropelAuth with React and Flask

!UPDATE: i'm now publishing here

Introduction

In the rapidly evolving world of web development, securing applications is a top priority. This blog post explores the integration of PropelAuth, an authentication solution, with a React frontend and a Flask backend. I found PropelAuth's documentation to be easily to follow and useful. As a learner, I appreciated the examples and use cases in addition to the code snippets.

Overview of Technologies

  • React: A popular JavaScript library for building user interfaces.

  • Flask: A lightweight and flexible Python web framework.

  • PropelAuth: A service offering authentication and authorization functionalities with minimal setup.

Setting Up PropelAuth

Before diving into the integration, it's essential to have a PropelAuth account. Once set up, you can create a new project and obtain the necessary API keys and configuration details.

Integrating with the React Frontend

  1. Installing PropelAuth SDK: Use npm to install the PropelAuth React SDK.

     npm install @propelauth/react
    

    Or enter it into your package.json directly.

  2. Initializing PropelAuth: In your main React file (like index.js or maybe App.js), initialize PropelAuth with the configuration obtained from your PropelAuth dashboard. *Note: I left my PropelAuth API in my .env. MAKE SURE YOU INCLUDE YOUR .env IN YOUR .gitignore first!

     import React from "react";
    
     import "./index.css";
     import { createRoot } from "react-dom/client";
     import { AuthProvider } from "@propelauth/react";
    
     const container = document.getElementById("root");
     const root = createRoot(container);
    
     root.render(
         <AuthProvider authUrl={process.env.REACT_APP_AUTH_URL}>
             <App />
         </AuthProvider>
     );
    
  3. Handling User Information: Access user information using the useful, descriptive hooks provided by the PropelAuth React library. Here's an example courtesy of PropelAuth that I also included in my project. It's a nice demonstration of PropelAuth hooks and the information you can render:

     import React from 'react';
     import { withAuthInfo, useRedirectFunctions, useLogoutFunction } from '@propelauth/react';
    
     // Local imports
     import Header from '../layout/Header';
    
     function UserProfile({ isLoggedIn, user }) {
       const {redirectToLoginPage, redirectToSignupPage, redirectToAccountPage} = useRedirectFunctions()
       const logoutFunction = useLogoutFunction()
    
       if (isLoggedIn) {
           return (
             <div>
               <Header />
               <span>
                 <h2>User Info</h2>
                 {user && user.pictureUrl && <img src={user.pictureUrl} className="pictureUrl" alt="profile pic" />}
                 <pre>user: {JSON.stringify(user, null, 2)}</pre>
               </span>
               <button onClick={redirectToAccountPage}>Account</button>
               <button onClick={logoutFunction }>Logout</button>
             </div>
           )
       } else {
           return (
             <div>
               <p>You are not logged in</p>
               <button onClick={redirectToLoginPage}>Login</button>
               <button onClick={redirectToSignupPage}>Signup</button>
             </div>
           )
       }
     }
    
     export default withAuthInfo(UserProfile);
    
  4. For more information and examples, please visit PropelAuth's useful and up to date documentation: https://docs.propelauth.com/reference/frontend-apis/react. As a new full stack developer, PropelAuth's documentation was the first one that I was able to successfully follow. It provided me enough guidance that I had my React front-end connected within a few hours.

Integrating with the Flask Backend

  1. Installing PropelAuth Backend SDK: Add the PropelAuth Python SDK to your Flask project. Depending on how you're managing your dependencies:

     pip install propelauth_flask
    
     or 
    
     pipenv install propelauth_flask
    
  2. Configuring PropelAuth: Initialize PropelAuth in your Flask application using the API key and other configuration details. This may look different depending on your setup. You can also see my Svix initialization here too. I'll talk more about Svix below. Again, just like my front end, I used an .env file to secure both my Svix and PropelAuth API information. MAKE SURE YOU INCLUDE .env IN YOUR .gitignore FIRST!

     # Your other imports
    
     # Load environment variables from .env file
     load_dotenv()
    
     # PropelAuth configuration environmental variables
     auth_url = os.getenv('PROPELAUTH_URL')
     api_key = os.getenv('PROPELAUTH_API_KEY')
    
     # Svix environmental variables
     svix_api_secret = os.getenv('SVIX_SIGNING_SECRET')
     svix_user_webhook_endpoint = os.getenv('SVIX_USER_WEBHOOK_ENDPOINT')
    
     app = Flask(__name__)
     app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
     app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
     app.json.compact = False
     auth = init_auth(auth_url, api_key)  # PropelAuth
    
     # Your other inits
    
  3. Securing API Endpoints: Use PropelAuth's decorators like @auth_required to protect your API routes. These decorators ensure that only authenticated requests can access specific endpoints.

  4. Receiving web hook alerts: In your PropelAuth admin page, go to "Notifications/Webhooks" to setup the Svix service. It was my first time using Svix and webhooks in general, and I found Svix user friendly and self explanatory. If your project isn't deployed yet, you can easily sign up for a free ngrok account to make the connection between your local development server and Svix. Svix's portal provides the schema for each event, and the ability to test it. So you can send a test data to your backend to make sure it works the way you want.

    So an example data flow would be:

    a) User signs up on your site through your PropelAuth setup.

    b) Svix sends you the relevant event (user created, user updated, etc.) information.

    c) It hits your Svix endpoint just like any other end point you create. As an example, here's my Svix endpoint. *NOTE: I left my api keys and such inside my .env. MAKE SURE YOU INCLUDE .env IN YOUR .gitignore FIRST!

  5.    class SvixWebhookHandler(Resource):
           def post(self):
               # Retrieve the raw payload
               payload = request.get_data(as_text=True)
    
               # Retrieve all headers from request
               headers = dict(request.headers)
    
               # Initialize a webhook verification object with api key
               verifier = Webhook(svix_api_secret)
    
               try:
                   # Verify the signature using the raw payload and all headers
                   verifier.verify(payload, headers)
               except WebhookVerificationError:
                   abort(401, "Invalid signature.")
    
               # If the signature is verified, now parse JSON payload
               payload_json = request.get_json()
    
               # Access the "event_type"
               event_type = payload_json["event_type"]
    
               if event_type == "user.created":
                   # Access the user information
                   email = payload_json["email"]
                   user_id = payload_json["user_id"]
                   first_name = payload_json.get("first_name")
                   last_name = payload_json.get("last_name")
                   username = payload_json.get("username")
                   picture_url = payload_json.get("picture_url")
                   create_user(email, user_id, picture_url, username, first_name, last_name)
    
               elif event_type == "user.deleted":
                   # Access the user ID
                   user_id = payload_json["user_id"]
                   delete_user(user_id)
    
               # Respond to Svix to acknowledge webhook receipt
               return {"status": "success"}, 200
    
       api.add_resource(SvixWebhookHandler, "/svix_user_webhook_endpoint")
    

d) Runs through your schema and service methods.

e) Hits your local db.

Again, PropelAuth has wonderful documentation and information to help you with back end integration.

I had a lot of fun learning how to integrate PropelAuth. As a bonus, I got to learn to use Svix and Ngrok too. I shared long snippets of my code because I know it can be helpful to other learners to see and read.

Did you find this article valuable?

Support Jia-Jia Zhu by becoming a sponsor. Any amount is appreciated!