JWT Authentication with FastAPI
Objective In this module, you will build a complete JWT-based authentication system using FastAPI. By the end of this module, you will be able to:- Create a User model using SQLAlchemy ORM.
- Securely hash and verify user passwords.
- Generate and validate JWT access tokens.
- Implement user registration and login APIs.
- Authenticate users using JWT.
- Protect REST APIs using authentication dependencies.
- Implement role-based authorization.
Architecture
Implementation Flow
- Create the Project Structure
- Configure the Database
- Create the User ORM Model
- Create the User Schemas
- Initialize the FastAPI Application
- Implement Authentication Utilities
- Implement the Register API
- Implement the Login API
- Implement the Current User Authentication Dependency
- Create Public and Protected APIs
- Test the Complete Authentication Flow
Step 1: Create the Project Structure
Objective Create the project structure and install the required libraries for implementing JWT authentication. Instructions Create a new FastAPI project and organize it using the following structure.- FastAPI
- Uvicorn
- SQLAlchemy
- pwdlib
- python-jose (with cryptography support)
Solution
Solution
Create the ProjectCreate a Virtual EnvironmentActivate the Virtual EnvironmentmacOS / LinuxWindowsInstall the Required LibrariesCreate the Project StructureThe project structure should look like this:
- The project has been created successfully.
- The virtual environment has been activated.
- All required libraries have been installed.
- The
appdirectory has been created. - All Python files have been created.
- The project structure matches the required layout.
Solution
Solution
Commit Changes
Create a Initialize the Git repository and commit the project.
.gitignore file with the following content.Step 2: Configure the Database
Objective Configure the SQLite database and implement the database session dependency. Instructions Create adatabase.py file and implement the following:
- Configure the SQLite database.
- Create the SQLAlchemy engine.
- Create the Base class.
- Implement the
get_db()dependency for managing database sessions.
Solution
Solution
app/database.py- The SQLite database URL has been configured.
- The SQLAlchemy engine has been created.
- The
Baseclass has been implemented. - The
get_db()dependency has been implemented.
Note: The users.db database file will be created automatically when the database tables are created in a later step.
Commit Changes
Solution
Solution
Step 3: Create the User ORM Model
Objective Create the User ORM model for storing user information in the SQLite database. Instructions Create amodels.py file and implement the User ORM model.
The model should contain the following fields:
- id
- name
- password
- role
idshould be the primary key.emailshould be unique.name,email, andpasswordshould be mandatory.roleshould default to"user".
Solution
Solution
app/models.py- The
Usermodel has been created. - The model inherits from
Base. - The table name is
users. - The
idfield is the primary key. - The
emailfield has a unique constraint. - The
rolefield has a default value of"user".
Note: The database table will be created in the next step when the FastAPI application is initialized.Commit Changes
Solution
Solution
Step 4: Create the User Schemas
Objective Create Pydantic schemas for validating API requests and formatting API responses. Instructions Create aschemas.py file and implement the following schemas:
UserCreateUserResponse
UserCreate schema should contain:
- name
- password
nameshould have a minimum length of 3 characters.nameshould have a maximum length of 50 characters.emailshould be a valid email address.passwordshould have a minimum length of 8 characters.
UserResponse schema should contain:
- id
- name
- role
Solution
Solution
app/schemas.py- The
UserCreateschema has been created. - The
UserResponseschema has been created. - The
namefield validates the minimum and maximum length. - The
emailfield accepts only valid email addresses. - The
passwordfield validates the minimum length. - The
UserResponseschema is configured to read data from ORM objects.
Solution
Solution
Step 5: Initialize the FastAPI Application
Objective Initialize the FastAPI application, create the database tables, and implement a simple Home endpoint. Instructions Open themain.py file and implement the following:
- Create a FastAPI application.
- Import the database engine.
- Import the User model.
- Create the database tables.
- Implement a Home endpoint.
Solution
Solution
app/main.py- The application starts successfully.
- A
users.dbdatabase file is created. - A
userstable is created in the database. - The Home endpoint is accessible.
Solution
Solution
Step 6: Implement Authentication Utilities
Objective Implement reusable helper functions for password hashing, password verification, JWT generation, and JWT validation. These helper functions will be used by the Register API, Login API, and Protected APIs. Instructions Create anauth.py file and implement the following:
- Configure the Secret Key.
- Configure the JWT Signing Algorithm.
- Configure the Token Expiration Time.
- Implement the
hash_password()function. - Implement the
verify_password()function. - Implement the
create_access_token()function. - Implement the
verify_access_token()function.
Solution
Solution
app/auth.py- The Secret Key has been configured.
- The JWT signing algorithm has been configured.
- The token expiration time has been configured.
- The password hashing utility has been implemented.
- The password verification utility has been implemented.
- The JWT generation utility has been implemented.
- The JWT validation utility has been implemented.
Note: These helper functions will be used in the upcoming steps to implement user registration, login, and protected REST APIs.Commit Changes
Solution
Solution
Step 7: Implement the Register API
Objective Implement the Register API to create a new user account. Before storing the user in the database, securely hash the password using the authentication utility. Instructions Open themain.py file and implement the Register API.
The API should perform the following:
- Accept user registration details.
- Validate the request using the
UserCreateschema. - Check whether the email already exists.
- Hash the password.
- Create a new user.
- Save the user to the database.
- Return the created user.
Solution
Solution
Update
app/main.py/register
Request Body
- The user is created successfully.
- A 201 Created response is returned.
- The password stored in the database is hashed.
- The response does not include the password.
- Registering the same email again returns 409 Conflict.
users.db database using DB Browser for SQLite and verify that the password column contains a hashed value instead of the original password.
Commit Changes
Solution
Solution
Step 8: Create the Authentication Schemas
Objective Create the Pydantic schemas required for user authentication. Instructions Open theschemas.py file and implement the following schemas:
- LoginRequest
- TokenResponse
LoginRequest schema should contain:
- password
TokenResponse schema should contain:
- access_token
- token_type
Solution
Solution
Update
app/schemas.py- The
LoginRequestschema has been created. - The
TokenResponseschema has been created. - The email field accepts valid email addresses.
- The password field uses the shared
Passwordvalidation.
Solution
Solution
Step 9: Implement the Login API
Objective Implement the Login API to authenticate a user and generate a JWT access token. Instructions Open themain.py file and implement the Login API.
Implementation Steps
Step 1: Import the required authentication utilities and schemas.
Step 2: Create the Login API endpoint.
Step 3: Retrieve the user using the email address.
Step 4: Verify that the user exists.
Step 5: Verify the entered password.
Step 6: Generate a JWT access token.
Step 7: Return the generated JWT to the client.
Task
Implement the Login API.
Solution
Solution
Update
app/main.py/login endpoint.
Request Body
- The user is authenticated successfully.
- A JWT access token is returned.
- The response contains the token type as
"bearer". - An invalid email returns 401 Unauthorized.
- An incorrect password returns 401 Unauthorized.
Note: Copy the generated JWT access token. It will be used in the next step to access the protected APIs.Commit Changes
Solution
Solution
Step 10: Implement the Current User Authentication Dependency
Objective Implement a dependency that authenticates the current user using a JWT access token. The dependency will:- Read the Bearer token from the request.
- Validate the JWT access token.
- Extract the user information from the JWT payload.
- Retrieve the authenticated user from the database.
- Return the authenticated user.
auth.py file and implement the current user authentication dependency.
Implementation Steps
Step 1: Import the required FastAPI security classes.
Step 2: Create an HTTPBearer security instance.
Step 3: Create a reusable database session dependency.
Step 4: Implement the get_current_user() dependency.
Step 5: Read the Bearer token from the request.
Step 6: Validate the JWT access token.
Step 7: Retrieve the authenticated user from the database.
Step 8: Return the authenticated user.
Task
Implement the current user authentication dependency.
Solution
Solution
Update
app/auth.py- The application starts successfully.
- The Authorize button appears in Swagger UI.
- A Bearer token can be entered using the Authorize dialog.
- The
get_current_user()dependency is implemented successfully.
Note: The get_current_user() dependency will be used in the next step to protect REST APIs.
Commit Changes
Solution
Solution
Step 11: Create Public and Protected APIs
Objective Create public and protected REST APIs to demonstrate JWT-based authentication. The Public API should be accessible without authentication, while the Protected API should only be accessible to authenticated users. Instructions Open themain.py file and implement the Public and Protected APIs.
Implementation Steps
Step 1: Import the get_current_user() dependency.
Step 2: Create a reusable dependency for the authenticated user.
Step 3: Implement a Public API.
Step 4: Implement a Protected API.
Step 5: Access the authenticated user’s information inside the Protected API.
Task
Create the Public and Protected APIs.
Solution
Solution
Update
app/main.py/public endpoint.
Verify that:
- The endpoint is accessible without authentication.
- A successful response is returned.
- Register a new user.
- Login using the registered user’s credentials.
- Copy the generated JWT access token.
- Click the Authorize button in Swagger UI.
- Enter the JWT token in the following format:
- Invoke the GET
/profileendpoint.
- The authenticated user’s details are returned.
- Accessing the endpoint without a token returns 401 Unauthorized.
- Accessing the endpoint with an invalid or expired token returns 401 Unauthorized.
Solution
Solution
Step 12: Test the Complete Authentication Flow
Objective Test the complete JWT authentication workflow by registering a user, logging in, obtaining a JWT access token, and accessing both public and protected APIs. Instructions Run the FastAPI application and verify that the authentication system works as expected.Test Scenarios
Step 1: Start the Application Run the application.Step 2: Register a New User Invoke the POST
/register endpoint.
Request Body
- The user is registered successfully.
- A 201 Created response is returned.
- The password is stored as a hashed value in the database.
Step 3: Login Invoke the POST
/login endpoint.
Request Body
- Login is successful.
- A JWT access token is returned.
Step 4: Access the Public API Invoke the GET
/public endpoint.
Verify that:
- The endpoint is accessible without authentication.
Step 5: Access the Protected API Click the Authorize button in Swagger UI. Enter the JWT access token.
/profile endpoint.
Verify that:
- The authenticated user’s details are returned.
Step 6: Verify Unauthorized Access Verify the following scenarios:
- Access
/profilewithout a JWT token. - Access
/profilewith an invalid JWT token. - Access
/profilewith an expired JWT token.
Expected Authentication Flow
- User registration works successfully.
- Login returns a valid JWT access token.
- Passwords are stored as hashed values.
- Public APIs are accessible without authentication.
- Protected APIs require a valid JWT.
- Invalid or expired tokens return 401 Unauthorized.
Solution
Solution