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:- Create the Project
- Create the User Model
- Implement Password Hashing
- Create the Default Admin User
- Implement User Registration
- Implement Login and Generate JWT
- Validate JWT
- Create the Authorization Dependency
- Create an Admin API to Assign Roles
- Create Role-Protected Endpoints
- 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 Unauthorizedand403 Forbiddenresponses.
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
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 namedrbac_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:userauthoradmin
Expected Outcome
At the end of this task, you should have:- A
Usermodel with arolefield. - Request models for registration and login.
- A
usertable with role information. - Default role assignment for new users.
Task 3 - Implement Password Hashing
Goal
Implement password hashing and password verification usingbcrypt.
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.
Run the Application
Verify
Open theuser 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 ofuser.
Update app.py
Import the required modules.
How It Works
- Receive the username and password.
- Check whether the username already exists.
- Hash the password.
- Assign the default role
user. - Store the user in the database.
- Return a success response.
Run the Application
Test the API
Open the Swagger UI.Verify
Open theuser 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 theuserrole. Only an administrator can promote users to roles such asauthororadmin.
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
userrole.
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.
Update app.py
Import the required modules.
JWT Claims
The generated JWT contains the following claims.Run the Application
Test the API
Open the Swagger UI.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 theAuthorization header and return the authenticated user.
Update auth.py
Import the required modules.
Nested Dependencies
Theauthenticate_user() function is itself a dependency and depends on two other dependencies.
HTTPBearer()extracts the JWT from theAuthorizationheader.get_session()provides a database session.
How It Works
- Read the Bearer token from the
Authorizationheader. - Validate the JWT signature.
- Verify that the token has not expired.
- Extract the user ID from the token.
- Retrieve the authenticated user from the database.
- Return the authenticated user.
- 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 Unauthorizedresponses 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
- Authenticate the user using the JWT.
- Retrieve the user’s role.
- Compare the user’s role with the allowed roles.
- Return the authenticated user if authorized.
- Return 403 Forbidden if the user does not have the required role.
Using the Dependency
Allow only administrators.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 Forbiddenresponses 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.
How It Works
- Authenticate the user.
- Verify that the user has the
adminrole. - Retrieve the target user.
- Validate the requested role.
- Update the user’s role.
- Save the changes to the database.
Run the Application
Test the API
Login as the default administrator.Expected Response
Verify
Open theuser 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 Forbiddenresponses 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.
Endpoint Access
How It Works
/publicis accessible to everyone./profilerequires authentication./authorrequires theauthororadminrole./adminrequires theadminrole.
Run the Application
Test the APIs
- Register a new user.
- Login and obtain a JWT.
- Call
/profile. - Login as the default administrator.
- Promote the user to the
authorrole. - Login again to obtain a new JWT.
- Call
/author. - 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).