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
Installing PropelAuth SDK: Use npm to install the PropelAuth React SDK.
npm install @propelauth/react
Or enter it into your package.json directly.
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> );
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);
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
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
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
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.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!
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.