DEV Community

Cover image for Implementing Basic Authentication in FastAPI
Gopinath V
Gopinath V

Posted on

Implementing Basic Authentication in FastAPI

Basic Authentication in your FastAPI applications! Whether you’re building a simple internal API or just getting started with API security, understanding Basic Auth is a fundamental step.

What is HTTP Basic Authentication?
HTTP Basic Authentication is the simplest form of authentication built directly into the HTTP protocol. It works by sending the user’s username and password (separated by a colon, then Base64 encoded) in the Authorization header of every HTTP request.

Example Authorization Header:

When a client tries to access a protected resource, the server responds with a 401 Unauthorized status and a WWW-Authenticate: Basic realm="" header. The client (usually a web browser or an API client like Postman/curl) then prompts the user for a username and password. These credentials are then combined (username:password), base64 encoded, and sent in the Authorization header of the subsequent request, like this:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== (where QWxhZGRpbjpvcGVuIHNlc2FtZQ== is the Base64 encoding of Aladdin:open sesame)

We will go by each step to start will prerequistes.

Prerequisites
Before we start, make sure you have Python installed (3.7+) and the necessary libraries:

pip install fastapi uvicorn "python-multipart[optional]" # python-multipart for form data, optional but good practice 
Enter fullscreen mode Exit fullscreen mode

Step 1: Project Setup

Let’s create a simple project structure.

 fastapi_basic_auth/ ├── main.py └── .env (optional, for storing sensitive data) 
Enter fullscreen mode Exit fullscreen mode

Step 2: Define Your Users (for demonstration)

For a real application, you’d fetch user credentials from a database. For this example, we’ll hardcode a few users. Never hardcode passwords in a real application! Always store hashed passwords in a database.

Open main.py and start by importing FastAPI and some authentication utilities from fastapi.security.

 # main.py from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import HTTPBasic, HTTPBasicCredentials import uvicorn # For running the app directly if desired app = FastAPI() security = HTTPBasic() # Initialize HTTPBasic authentication # Hardcoded users for demonstration. In a real app, fetch from DB! # Passwords should ALWAYS be hashed (e.g., using bcrypt) in a real app. USERS_DB = { "admin": "supersecret", "john.doe": "password123", "jane.smith": "securepass" } # Dummy function to simulate password verification (replace with bcrypt.checkpw in real app) def verify_password(plain_password: str, stored_password: str) -> bool: # In a real app, this would be e.g., bcrypt.checkpw(plain_password.encode(), stored_password_hash) return plain_password == stored_password 
Enter fullscreen mode Exit fullscreen mode

Security Note: The USERS_DB and verify_password function here are highly insecure for production. They are purely for demonstrating the authentication flow. In a real application, you'd use libraries like passlib (with bcrypt or scrypt) to hash and verify passwords securely.

Step 3: Create the Authentication Dependency

FastAPI’s dependency injection system is perfect for handling authentication. We’ll create a function that verifies the provided credentials.

main.py (continued)

 # ... (previous imports and USERS_DB, verify_password function) ... def get_current_username(credentials: HTTPBasicCredentials = Depends(security)): """ Dependency to get and verify the current user's username based on Basic Auth. """ username = credentials.username password = credentials.password if username not in USERS_DB: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"}, ) if not verify_password(password, USERS_DB[username]): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"}, ) return username # Return the username if authentication is successful 
Enter fullscreen mode Exit fullscreen mode

Explanation of get_current_username:

credentials: HTTPBasicCredentials = Depends(security):
HTTPBasicCredentials is a Pydantic model (provided by FastAPI) that will automatically parse the Authorization header for Basic Auth, extracting username and password.
Depends(security): This tells FastAPI to:
Check for the Authorization: Basic header.
If not present or malformed, return a 401 Unauthorized with the WWW-Authenticate: Basic header, prompting the client for credentials.
If present, decode the credentials and inject them into the credentials parameter as an HTTPBasicCredentials object.
Verification Logic:
We first check if the username exists in our USERS_DB.
Then, we use verify_password to compare the provided password with the stored one.
HTTPException: If authentication fails at any point, we raise an HTTPException with:
status.HTTP_401_UNAUTHORIZED: The standard HTTP status code for unauthorized access.
detail: A custom message for the client.
headers={"WWW-Authenticate": "Basic"}: This crucial header tells the client (especially browsers) how to authenticate, prompting the browser's native login dialog.
Return username: If both checks pass, the function returns the username. This username can then be used by your endpoint function.

Step 4: Protect Your API Endpoints

Now, you can use this get_current_username dependency to protect your routes.

main.py (continued)

 # ... (previous code) ... @app.get("/unprotected/") async def unprotected_route(): """An endpoint that doesn't require authentication.""" return {"message": "This endpoint is open to everyone!"} @app.get("/protected/") async def protected_route(username: str = Depends(get_current_username)): """ An endpoint that requires Basic Authentication. The 'username' parameter will receive the authenticated username. """ return {"message": f"Welcome, {username}! You accessed a protected endpoint."} @app.get("/protected-admin/") async def protected_admin_route(username: str = Depends(get_current_username)): """ An endpoint that requires Basic Authentication and checks for 'admin' role. """ if username != "admin": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You do not have permission to access this resource.", ) return {"message": f"Hello, Admin {username}! This is a top-secret route."} 
Enter fullscreen mode Exit fullscreen mode

Explanation of Endpoint Usage:

/unprotected/: No Depends on get_current_username, so it's publicly accessible.
/protected/: By adding username: str = Depends(get_current_username), this endpoint now requires Basic Authentication. If authentication succeeds, the username variable inside the function will hold the authenticated username.
/protected-admin/: This demonstrates adding authorization logic after authentication. Once the user is authenticated, we check if their username is "admin" to grant access to this specific resource. If not, a 403 Forbidden is returned.

Step 5: Run Your FastAPI Application

To run your application, use Uvicorn from your terminal. Navigate to the directory containing main.py.

uvicorn main:app --reload --port 8000 
Enter fullscreen mode Exit fullscreen mode

main: Refers to your main.py file.
app: Refers to the FastAPI() instance named app inside main.py.
--reload: Useful for development; Uvicorn will restart whenever you save changes.
--port 8000: Runs the server on port 8000.
You should see output similar to:

INFO: Will watch for changes in these directories: ['/path/to/your/fastapi_basic_auth'] INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started reloader process [xxxxx] INFO: Started server process [xxxxx] INFO: Waiting for application startup. INFO: Application startup complete. 
Enter fullscreen mode Exit fullscreen mode

Step 6: Test Your Endpoints

Open your web browser or an API client like Postman/Insomnia.

  1. Access http://127.0.0.1:8000/unprotected/:
  • You should see: {"message":"This endpoint is open to everyone!"}. No authentication requi red.
  • Access http://127.0.0.1:8000/protected/:

  • In a Browser: Your browser will pop up a native Basic Auth login dialog.
    Try:

  • Username: wrong_user, Password: any_password -> You'll get 401 Unauthorized repeatedly.

  • Username: john.doe, Password: password123 -> You should see: {"message":
    "Welcome, john.doe! You accessed a protected endpoint."}.

  • Access http://127.0.0.1:8000/protected-admin/:

  • Try with john.doe:password123: You'll get {"detail":"You do not have permission to access this resource."} (Status 403 Forbidden).

  • Try with admin:supersecret: You should see: {"message":"Hello, Admin admin! T
    his is a top-secret route."}.

    Important Security Considerations for Production

    As mentioned, Basic Auth is simple but has limitations. Always use HTTPS in production! Without it, the base64-encoded credentials are easily intercepted. For more robust security, consider these alternatives:

  • OAuth 2.0 / OpenID Connect: The industry standard for user authentication and authorization, providing token-based security, refresh tokens, and more complex flows suitable for public-facing applications. Libraries like Authlib can help.

  • JWT (JSON Web Tokens): Often used in conjunction with Bearer Token authentication. JWTs can carry signed (and optionally encrypted) claims, allowing stateless authentication. FastAPI has excellent support for JWTs.
    API Key Management: If using API keys, ensure they are:

  • Revocable.

  • Have expiration dates.

  • Associated with specific user accounts or roles for fine-grained control.

Top comments (0)