Skip to main content

Role-Based Authorization

In the previous section, we implemented JWT Authentication, where users proved their identity by presenting a valid JSON Web Token (JWT). Authentication answers the question:
Who are you?
However, once a user is authenticated, we still need to determine what they are allowed to do. This is the responsibility of Authorization. In this section, we will implement Role-Based Access Control (RBAC) by assigning roles to users and restricting access to API endpoints based on those roles.

What We Will Implement

  • Add roles to users.
  • Assign roles during registration.
  • Include the user’s role in the JWT.
  • Create reusable authorization dependencies.
  • Restrict endpoints based on roles.
  • Return appropriate authorization errors.

Authentication vs Authorization

Roles

For this project, we will use three roles.

Authorization Flow

APIs

Implementation Plan

We will complete this implementation in the following tasks:
  1. Create the Project
  2. Create the User Model
  3. Implement Password Hashing
  4. Create the Default Admin User
  5. Implement User Registration
  6. Implement Login and Generate JWT
  7. Validate JWT
  8. Create the Authorization Dependency
  9. Create an Admin API to Assign Roles
  10. Create Role-Protected Endpoints
  11. Test Role-Based Authorization

Learning Outcomes

After completing this section, you will be able to:
  • Understand the difference between authentication and authorization.
  • Implement Role-Based Access Control (RBAC).
  • Restrict endpoints based on user roles.
  • Reuse authorization dependencies across multiple APIs.
  • Return appropriate 401 Unauthorized and 403 Forbidden responses.

Task 1 - Create the Project

Goal

Create a new FastAPI project for implementing Role-Based Authorization using JWT Authentication and SQLite.

Create the Project

Installed Packages

Create the Project Structure

Create the required files. Windows
macOS / Linux

Update database.py

Update app.py

Run the Application

Verify

Open the following URLs:

Expected Outcome

At the end of this task, you should have:
  • A new FastAPI project.
  • All required dependencies installed.
  • A configured SQLite database.
  • A running FastAPI application.
  • The project ready for implementing Role-Based Authorization.

Task 2 - Create the User Model

Goal

Create the database models required for implementing Role-Based Authorization.

Update models.py

Run the Application

Verify

After starting the application, a new SQLite database named rbac_auth.db should be created with a user table containing the following columns.

Default Role

If no role is specified during registration, the user is assigned the default role.

Supported Roles

For this project, we will use the following roles:
  • user
  • author
  • admin

Expected Outcome

At the end of this task, you should have:
  • A User model with a role field.
  • Request models for registration and login.
  • A user table with role information.
  • Default role assignment for new users.

Task 3 - Implement Password Hashing

Goal

Implement password hashing and password verification using bcrypt.

Update auth.py

Run the File

Expected Output

Why Hash Passwords?

Passwords should never be stored as plain text. Instead, only their hashed values are stored in the database. During authentication, the entered password is verified against the stored hash.

Expected Outcome

At the end of this task, you should have:
  • A reusable password hashing function.
  • A reusable password verification function.
  • A secure mechanism for storing user passwords.

Task 4 - Create the Default Admin User

Goal

Automatically create an administrator account when the application starts.

Update app.py

Import the required modules.
Add the following function.
Call the function after creating the database tables.

Run the Application

Verify

Open the user table in the SQLite database. The following user should be created automatically.
Note: The password stored in the database will be a hashed value, not admin123.

Expected Outcome

At the end of this task, you should have:
  • A default administrator account.
  • Automatic admin creation only if it does not already exist.
  • An administrator ready to manage user roles.

Task 5 - Implement User Registration

Goal

Create an API to register new users. Every newly registered user is assigned the default role of user.

Update app.py

Import the required modules.
Implement the registration endpoint.

How It Works

  1. Receive the username and password.
  2. Check whether the username already exists.
  3. Hash the password.
  4. Assign the default role user.
  5. Store the user in the database.
  6. Return a success response.

Run the Application

Test the API

Open the Swagger UI.
Call:
Request Body

Verify

Open the user table in the SQLite database. A new record should be created similar to:
Note: Users cannot choose their own role during registration. Every new user is assigned the user role. Only an administrator can promote users to roles such as author or admin.

Expected Outcome

At the end of this task, you should have:
  • A working user registration API.
  • Duplicate username validation.
  • Passwords stored securely using hashing.
  • Automatic assignment of the default user role.

Task 6 - Implement Login and Generate JWT

Goal

Authenticate users using their username and password. Upon successful authentication, generate a JWT containing the user’s identity and role.

Update auth.py

Import the required modules.
Add the following constants.
Implement the JWT generation function.

Update app.py

Import the required modules.
Implement the login endpoint.

JWT Claims

The generated JWT contains the following claims.

Run the Application

Test the API

Open the Swagger UI.
Call:
Request Body

Expected Response

Verify

Paste the generated token into the JWT debugger: :contentReference[oaicite:0] The decoded payload should contain:

Expected Outcome

At the end of this task, you should have:
  • A working login API.
  • Username and password verification.
  • JWT generation.
  • The user’s role included in the JWT.
  • A signed access token returned to the client.

Task 7 - Validate JWT and Authenticate Users

Goal

Validate the JWT received in the Authorization header and return the authenticated user.

Update auth.py

Import the required modules.
Implement the authentication dependency.

Nested Dependencies

The authenticate_user() function is itself a dependency and depends on two other dependencies.
  • HTTPBearer() extracts the JWT from the Authorization header.
  • get_session() provides a database session.

How It Works

  1. Read the Bearer token from the Authorization header.
  2. Validate the JWT signature.
  3. Verify that the token has not expired.
  4. Extract the user ID from the token.
  5. Retrieve the authenticated user from the database.
  6. Return the authenticated user.
  7. Return 401 Unauthorized if authentication fails.

Authorization Header

The client must send the JWT as a Bearer token.

Expected Outcome

At the end of this task, you should have:
  • A reusable JWT authentication dependency.
  • JWT signature validation.
  • Token expiration validation.
  • Retrieval of the authenticated user.
  • Proper 401 Unauthorized responses for invalid or expired tokens.

Task 8 - Create the Authorization Dependency

Goal

Create a reusable dependency to authorize users based on their roles.

Update auth.py

Implement the authorization dependency.

How It Works

  1. Authenticate the user using the JWT.
  2. Retrieve the user’s role.
  3. Compare the user’s role with the allowed roles.
  4. Return the authenticated user if authorized.
  5. Return 403 Forbidden if the user does not have the required role.

Using the Dependency

Allow only administrators.
Allow administrators and authors.
Allow any authenticated user.

Nested Dependency Flow

Expected Outcome

At the end of this task, you should have:
  • A reusable authorization dependency.
  • Role validation for authenticated users.
  • Support for one or more allowed roles.
  • Proper 403 Forbidden responses for unauthorized users.

Task 9 - Create an Admin API to Assign Roles

Goal

Allow only administrators to assign roles to existing users.

Update models.py

Add the following request model.

Update app.py

Import the required modules.
Implement the role assignment endpoint.

How It Works

  1. Authenticate the user.
  2. Verify that the user has the admin role.
  3. Retrieve the target user.
  4. Validate the requested role.
  5. Update the user’s role.
  6. Save the changes to the database.

Run the Application

Test the API

Login as the default administrator.
Use the returned JWT to authorize in Swagger UI. Call:
Request Body

Expected Response

Verify

Open the user table in the SQLite database. The selected user’s role should be updated.

Expected Outcome

At the end of this task, you should have:
  • An administrator-only API for assigning roles.
  • Validation of supported roles.
  • Proper 403 Forbidden responses for non-admin users.
  • Role information stored in the database.

Task 10 - Create Role-Protected Endpoints

Goal

Protect API endpoints using Role-Based Authorization.

Update app.py

Import the required modules.
Implement the following endpoints.

Endpoint Access

How It Works

  • /public is accessible to everyone.
  • /profile requires authentication.
  • /author requires the author or admin role.
  • /admin requires the admin role.

Run the Application

Test the APIs

  1. Register a new user.
  2. Login and obtain a JWT.
  3. Call /profile.
  4. Login as the default administrator.
  5. Promote the user to the author role.
  6. Login again to obtain a new JWT.
  7. Call /author.
  8. Verify that only administrators can access /admin.
Note: If a user’s role changes, they should log in again to obtain a new JWT containing the updated role.

Expected Outcome

At the end of this task, you should have:
  • Public endpoints.
  • Authenticated endpoints.
  • Author-only endpoints.
  • Admin-only endpoints.
  • A complete implementation of Role-Based Authorization (RBAC).