1. Integrate your backend
  2. Flask Backend Integration

For the full Flask Library Reference, click here.

Quick Example

The following example creates a route which can only be accessed from logged-in users.

from flask import Flask
from propelauth_flask import init_auth, current_user

app = Flask(__name__)
auth = init_auth("YOUR_AUTH_URL", "YOUR_API_KEY")

@app.route("/api/whoami")
@auth.require_user
def who_am_i():
    return {"user_id": current_user.user_id}

You can find your Auth URL and API key(s) under the Backend Integration section for your project at https://app.propelauth.com

How it works

For a detailed description of what’s going on under the hood, see here.

Installation

In your Flask app, install the propelauth_flask library.

$ pip install propelauth-flask

Initialize

init_auth performs a one-time initialization of the library. It will verify your api_key is correct and fetch the metadata needed to verify access tokens in require_user, optional_user, or require_org_member.

from propelauth_flask import init_auth

auth = init_auth("YOUR_AUTH_URL", "YOUR_API_KEY")

Protect API routes

require_user

A decorator that will verify the request was made by a valid user. Specifically, it will:

  1. Check that a valid access token was provided. If not, the request is rejected with a 401 status code.
  2. Set current_user (scoped to the current request) with the user’s information.
from flask import Flask
from propelauth_flask import init_auth, current_user

app = Flask(__name__)
auth = init_auth("YOUR_AUTH_URL", "YOUR_API_KEY")

@app.route("/api/whoami")
@auth.require_user
def who_am_i():
    """This route is protected, current_user is always set"""
    return {"user_id": current_user.user_id}

optional_user

Similar to require_user, except if an access token is missing or invalid, the request is allowed to continue, but current_user.exists() will be False.

from flask import Flask
from propelauth_flask import init_auth, current_user

app = Flask(__name__)
auth = init_auth("YOUR_AUTH_URL", "YOUR_API_KEY")

@app.route("/api/whoami_optional")
@auth.optional_user
def who_am_i_optional():
    if current_user.exists():
        return {"user_id": current_user.user_id}
    return {}

current_user

A per-request value that contains user information for the user making the request. It’s set by one of require_user, optional_user, or require_org_member.

PropertyDescription
user_idThe id of the user
org_id_to_org_member_infoA dictionary of org ids to metadata about the org. Includes all orgs that the user is in
legacy_user_idThe original ID of the user, if the user was migrated from an external source
exists()A function that returns True if the user is logged in and False otherwise. You only need to check this if you are using optional_user, otherwise it always returns True.

The values of org_id_to_org_member_info are OrgMemberInfo’s, with the following fields/functions:

PropertyDescription
org_idThe id of the org
org_nameThe name of the org
user_assigned_roleThe user’s role within the organization. See Roles and Permissions for more details.
user_is_role(role: str): boolReturns True if the user’s role within the organization matches the role passed in
user_is_at_least_role(role: str): boolReturns True if the user’s role within the organization is at least the role passed in. If the hierarchy of roles is Owner => Admin => Member, specifying “Admin” will return True for Admins and Owners, but False for Members.
user_has_permission(permission: str): boolReturns True if the user has a specific permission. The users’ permissions are derived from their role within this organization.
user_has_all_permissions(permissions: List[str]): boolReturns True if the user has all the specified permissions. The users’ permissions are derived from their role within this organization.

require_org_member

A decorator that will verify the request was made by a valid user that belongs to a specific organization.

@app.route("/org/<org_id>/check")
@auth.require_org_member()
def hello(org_id):
   return f"You are in {current_org.org_name}"
require_org_member ArgumentDescription
req_to_org_idA function that takes in the request and outputs the org_id to require the user to be a member of. If none is specified, it will check for a path param org_id.

Specifically, it will:

  1. Check that a valid access token was provided. If not, the request is rejected with a 401 status code.
  2. Set current_user (scoped to the current request) with the user’s information.
  3. Find an id for an organization within the request. By default, it will check for a path parameter org_id.
  4. Check that the user is a member of that organization. If not, the request is rejected with a 403 status code.
  5. Set current_org (scoped to the current request) with the organization’s information for this user.

current_org

A per-request value that contains org information for the user making the request. It’s set by require_org_member.

PropertyDescription
org_idThe id of the org
org_nameThe name of the org
user_assigned_roleThe user’s role within the organization. See Roles and Permissions for more details.
user_is_role(role: str): boolReturns True if the user’s role within the organization matches the role passed in
user_is_at_least_role(role: str): boolReturns True if the user’s role within the organization is at least the role passed in. If the hierarchy of roles is Owner => Admin => Member, specifying “Admin” will return True for Admins and Owners, but False for Members.
user_has_permission(permission: str): boolReturn True if the user has a specific permission. The users’ permissions are derived from their role within this organization.
user_has_all_permissions(permissions: List[str]): boolReturn True if the user has all the specified permissions. The users’ permissions are derived from their role within this organization.

Roles and Permissions

A user has a Role within an organization. By default, the available roles are Owner, Admin, or Member, but these can be configured. These roles are also hierarchical, so Owner > Admin > Member.

Roles allow you to control what different users can do within your product. If you want to check a user’s role, you can use auth.require_org_member_with_exact_role or auth.require_org_member_with_minimum_role.

## Assuming a Role structure of Owner => Admin => Member

@app.route("/org/<org_id>/admin")
@auth.require_org_member_with_exact_role("Admin")
def admin(org_id):
   return f"You are an Admin of {current_org.org_name}"

@app.route("/org/<org_id>/admin_or_owner")
@auth.require_org_member_with_minimum_role("Admin")
def admin_or_owner(org_id):
   return f"You are an Admin or Owner of {current_org.org_name}"

Permissions are arbitrary strings associated with a role. For example, can_view_billing, ProductA::CanCreate, and ReadOnly are all valid permissions. The PropelAuth dashboard allows you to set up these permissions.

You can use auth.require_org_member_with_permission or auth.require_org_member_with_all_permissions to check for a given permission.

@app.route("/org/<org_id>/billing")
@auth.require_org_member_with_permission("can_view_billing")
def billing(org_id):
   pass

All of these functions, just like require_org_member, will also take in req_to_org_id, and will set both current_user and current_org on a valid request.

API calls

In addition to protecting API routes, you can make requests to PropelAuth to fetch more information about your users or organizations. You can also create new users, update user metadata, and more.

See Flask Library Reference for more information on available functionality.

Next Steps

Done with your backend? Next you can deploy to production.