Hello! Welcome back to our course on building APIs with FastAPI.
In our last lesson, you built a crucial piece of our security system: a dependency that protects endpoints by verifying a JSON Web Token (JWT). You used it to create a /users/me endpoint that identifies the logged-in user.
Today, we will take the next logical step. It's not enough to just know who the user is; a truly secure and functional API uses that identity to control what the user can do. You will learn to access the authenticated user's data within your endpoints to assign ownership of new resources and enforce authorization rules.
By the end of this lesson, you will be able to confidently:
- Use the
current_userobject to automatically assign ownership when a new resource is created. - Implement authorization checks to ensure users can only modify or delete their own data.
- Differentiate between authentication (
401) and authorization (403) errors in practice. - Create endpoints that return data filtered specifically for the logged-in user.
This is a critical skill for your goal of deploying AI models. For example, you might need to save a user's prediction history or allow them to manage datasets they've uploaded—all of which rely on the principles of ownership and authorization we'll cover today.
A Quick Recap: The get_current_user Dependency
Remember the get_current_user dependency you created? It's the engine for everything we're doing in this lesson. On any request to a protected endpoint, it:
- Extracts the JWT from the
Authorizationheader. - Decodes and validates the token.
- Fetches the corresponding user object from the database.
- Makes that full SQLAlchemy
Userobject available to our endpoint function.
This means that within any protected endpoint, we have a trusted current_user variable that holds all the information about the person making the request.
Step 1: Assigning Ownership on Resource Creation
A major security flaw in many APIs is allowing the client to specify the owner of a new resource. For example, letting a user send {"title": "My Post", "content": "...", "user_id": 5} in a request body would allow them to create a post on behalf of user 5.
The correct approach is to determine the owner from the trusted JWT. Let's implement this for your "create post" endpoint.
First, you'll need to modify your Pydantic schema for creating posts to remove the user_id field. The client should only send the title and content. Your dependency will handle the rest.
Next, you will modify the create_post endpoint to use the current_user dependency to set the owner.
The following video provides an excellent, practical walkthrough of this exact process. It also introduces a CurrentUser type alias using typing.Annotated, a modern Python feature that makes your endpoint signatures cleaner and more readable.
Python FastAPI Tutorial (Part 11): Authorization - Protecting Routes and Verifying Current User
Watch this segment from Corey Schafer's "Python FastAPI Tutorial (Part 11)" to see how to securely associate a new post with the authenticated user.
Starting around the six-minute mark, watch the authentication implementation. Pay close attention to: The creation of the CurrentUser type alias using Annotated. Removing the user_id from the Pydantic PostCreate schema. Adding the current_user dependency to the create_post function. Using current_user.id to set the post's owner ID before saving it to the database.
After watching the video, update your own code to implement this pattern. By doing this, you've made your API more secure and improved the user experience—the client no longer needs to know or provide its own user ID.
Step 2: Enforcing Authorization with Ownership Checks
Now that posts are correctly associated with their owners, we must ensure that only the owner can modify or delete them. This is authorization—determining if an authenticated user has permission to perform a specific action.
The logic is straightforward:
- Protect the
updateanddeleteendpoints with yourcurrent_userdependency. - Inside the endpoint, first fetch the resource (e.g., the post) the user is trying to modify.
- Compare the resource's owner ID (
post.user_id) with the ID of the person making the request (current_user.id). - If they don't match, raise an
HTTPExceptionwith a403 Forbiddenstatus code.
A 403 Forbidden error tells the client: "We know who you are, and you are not allowed to do this." This is distinct from the 401 Unauthorized error, which means "We don't know who you are."
The next part of the same video demonstrates this perfectly.
Python FastAPI Tutorial (Part 11): Authorization - Protecting Routes and Verifying Current User
This segment shows how to add ownership checks to your update and delete endpoints, a core concept of API authorization.
Starting about nine and a half minutes in, watch the ownership checks. Focus on: The logic for the ownership check: if post.user_id != current_user.id. Why a 403 Forbidden status code is used instead of 401 Unauthorized. How this check is added to both the full update (PUT) and partial update (PATCH) endpoints, as well as the delete endpoint.
Go ahead and apply these authorization checks to your update_post and delete_post endpoints.
Step 3: Hands-On Test Drive
Theory is one thing, but seeing it in action is what solidifies learning. Let's run a test scenario to confirm our ownership rules are working correctly.
- Start fresh: Delete your SQLite database file to ensure a clean slate, then run your FastAPI application.
- Create User A: Go to the
/docspage and create a new user (e.g.,userA@example.com). - Log in as User A: Use the
Authorizebutton in Swagger UI to log in asUser Aand get a token. - Create Post 1: As
User A, create a new post. Note its ID (it should be 1). - Create User B: Log out (clear the authorization in Swagger). Create a second user (e.g.,
userB@example.com). - Log in as User B: Authorize as
User B. - Test the Rule: Attempt to update or delete
Post 1(the one created byUser A).
You should receive a 403 Forbidden error with the detail message you configured, proving that your authorization logic is working!
This testing flow is demonstrated visually in the video.
Python FastAPI Tutorial (Part 11): Authorization - Protecting Routes and Verifying Current User
Watch this clip to see a full test of the authorization logic, including creating multiple users and attempting to modify another user's content.
Starting about 16 minutes in, watch the authorization testing. This will walk you through the exact testing scenario described above using the interactive docs.

Step 4: Retrieving User-Specific Data
The final common use case is creating an endpoint that lists resources belonging only to the authenticated user. Let's build a new endpoint, GET /posts/me, that returns all posts created by the current user.
This brings together everything you've learned: a protected endpoint and a database query filtered by the current user's ID.
In your posts router file, add a new endpoint like this:
from typing import List
from .. import schemas, models, auth_utils # Adjust imports as needed
from sqlalchemy.orm import Session
from sqlalchemy import select
# ... (your router setup)
@router.get("/me", response_model=List[schemas.Post])
async def get_my_posts(
db: Session = Depends(database.get_db),
current_user: models.User = Depends(auth_utils.get_current_user)
):
"""
Retrieve all posts created by the currently authenticated user.
"""
# Create a query to select posts where the user_id matches the current user's id
query = select(models.Post).where(models.Post.user_id == current_user.id)
result = await db.execute(query)
posts = result.scalars().all()
return posts
Dissecting this endpoint:
- It's protected by
Depends(auth_utils.get_current_user), so we have access to thecurrent_userobject. - The SQLAlchemy query is simple but powerful:
select(models.Post).where(models.Post.user_id == current_user.id). It filters thePosttable to find only those records whoseuser_idmatches the ID of the person making the request. - It returns a list of posts, correctly serialized by the
response_model.
Add this endpoint to your application and test it. After creating posts with both User A and User B, you should see that calling this endpoint while logged in as User A only returns posts made by User A.
Conclusion
Excellent work! You have now mastered a fundamental aspect of secure API development. You've moved beyond simple authentication to implement robust authorization, ensuring users can only interact with their own data.
Key Takeaways:
- The authenticated
current_userobject is the trusted source for a user's identity within an endpoint. - Ownership of new data should always be assigned on the server-side using the
current_user.id, never from the request body. - Authorization logic (
403 Forbidden) prevents users from accessing or modifying resources they don't own. - You can easily create endpoints that provide a personalized view of data by filtering database queries with
current_user.id.
With a fully functional and secure CRUD API for users and posts, you are now well-prepared to tackle the primary goal of this course. In the next module, we will begin integrating a machine learning model into our FastAPI application, creating a prediction endpoint that we can secure using the authentication and authorization skills you've just honed.