RBAC Authorization with FastAPI and PropelAuth
Tags: python, webdev, security, startup
Published: 2023-03-04 23:23:19

Role-based access control (RBAC) is a method of deciding who gets access to what based on their role.

As an example, let's say we are building a product that allows teams to chat with their coworkers. Within a team, each user is either an **Admin** or a **Member**. We want to let all users view/send chat messages (**Admin**s and **Member**s), but only **Admin**'s can update billing information. This is a simple form of RBAC.

![Roles](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqdg0duxsxd4l6u8xanf.png)

Let's take that same example, write it out in code, and explain how it works:

```py
import os
from dotenv import load_dotenv
from fastapi import Depends, FastAPI
from propelauth_fastapi import init_auth, User

load_dotenv()

app = FastAPI()
auth = init_auth(os.getenv("PROPELAUTH_AUTH_URL"), os.getenv("PROPELAUTH_API_KEY"))

@app.get("/api/org/{org_id}/messages")
async def view_messages(org_id: str, current_user: User = Depends(auth.require_user)):
    org = auth.require_org_member(current_user, org_id)
    return fetch_messages(org.org_id)

@app.get("/api/org/{org_id}/billing")
async def view_billing(org_id: str, current_user: User = Depends(auth.require_user)):
    org = auth.require_org_member_with_minimum_role(current_user, org_id, "Admin")
    return fetch_billing_info(org.org_id)
```

#### **What does init\_auth do?**

[**init\_auth**](https://docs.propelauth.com/reference/backend-apis/fastapi.html#init-auth) fetches metadata from PropelAuth that it will use to verify users. It does this once on startup, so that it can verify users without making any external requests.

#### **How does require\_user work?**

When your frontend makes a request to the backend, it will include a token for the user that made the request. [**require\_user**](https://docs.propelauth.com/reference/backend-apis/fastapi.html#require-user) verifies this token (using the metadata it fetched in [**init\_auth**](https://docs.propelauth.com/reference/backend-apis/fastapi.html#init-auth)) and injects the User into the request. If invalid credentials are provided, the request is rejected.

#### **What is an org\_id?**

It's an identifier for an organization. PropelAuth provides B2B authentication meaning that your users can create organizations, invite their coworkers to join them, and manage roles within the organization.

#### **Where do the user and org\_id come from?**

PropelAuth provides end-to-end authentication, and one component of that is a configurable UI (hosted on your domain) for your users to sign up through. Another aspect is a UI for creating/joining organizations, inviting coworkers to those organizations, and letting these users manage permissions within their organization.

![Pick roles](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5c5431f169apdvd5h3oq.png)

A customized UI where a user is managing the Acme Organization

After the user signs up, a secure, HTTP-only cookie is created. We provide [**frontend libraries**](https://docs.propelauth.com/getting-started/frontend-integration/) so your frontend can understand if a user is currently logged in or not based on that cookie. These libraries can also fetch which organizations the user is a member of or a short-lived token for the current user - which the backend can verify and understand who made the request.

In React, for example, this might look like this:

```jsx
import {withAuthInfo} from "@propelauth/react";
import {useEffect, useState} from "react";

// accessToken and orgHelper are automatically injected from withAuthInfo
function AuthenticatedRequestToBilling({accessToken, orgHelper}) {
    const [response, setResponse] = useState(null)

    // A user can be in multiple orgs - get the one they are currently interacting with
    const selectedOrg = orgHelper.useActiveOrg()
    useEffect(() => {
        fetchBilling(accessToken, selectedOrg?.orgId).then(setResponse)
    }, [accessToken, selectedOrg?.orgId])

    return <span>
        <h2>Server Response</h2>
        <pre>{response ? JSON.stringify(response, null, 2) : "Loading..."}</pre>
    </span>
}

function fetchBilling(accessToken, orgId) {
    return fetch(`/api/org/${orgId}/billing`, {
        headers: {
            "Content-Type": "application/json",
            "Authorization": `Bearer ${accessToken}`
        }
    }).then(response => {
        if (response.ok) {
            return response.json()
        } else {
            return {status: response.status}
        }
    })
}

export default withAuthInfo(AuthenticatedRequestToBilling);
```

You don't have to worry about managing invitations, designing emails, or dealing with role changes - it's all already provided out of the box.

#### **What happens if the user isn't a member of that organization?**

`require_org_member` will fail and reject the request. This is encoded in the token so it also will not make any external requests.

‍‍

If you are interested in using [**PropelAuth**](https://www.propelauth.com/), you can sign up [here](https://auth.propelauth.com/signup) or reach out at [**support@propelauth.com**](mailto:support@propelauth.com) and we'd be happy to answer any questions you have.