Published on

Adding API Key Authentication to a FastAPI application

Authors
  • avatar
    Name
    Josh Di Mella
    Twitter
  1. Understanding API Key Authentication
  2. Adding API Key Authentication to FastAPI
  3. Complete Example
  4. Conclusion

FastAPI is a modern and high-performance web framework for building APIs with Python 3.6+. If you're using FastAPI to develop your API, it's essential to incorporate proper security measures to protect your routes from unauthorized access.

In this article, we'll explore how to add API Key authentication to your FastAPI application, ensuring secure and controlled access to your API endpoints.

Understanding API Key Authentication

API Key authentication is a common method used to secure API endpoints. It involves providing a unique key to clients, which they must include in their requests to authenticate themselves. By validating the API Key, you can control access to specific routes and ensure that only authorized clients can access them.

Adding API Key Authentication to FastAPI

Let's dive into the process of adding API Key authentication to your FastAPI application. We'll walk through the necessary steps and provide code examples along the way.

Step 1: Define a List of Valid API Keys

First, you need to define a list of valid API keys that your FastAPI application will accept. These keys will be used to authenticate client requests. Here's an example of how you can define the list:

API_KEYS = [
    "9d207bf0-10f5-4d8f-a479-22ff5aeff8d1",
    "f47d4a2c-24cf-4745-937e-620a5963c0b8",
    "b7061546-75e8-444b-a2c4-f19655d07eb8",
]

You can add as many keys as needed, and it's recommended to store them securely, such as in environment variables or a database.

Step 2: Implement API Key Security Function

Next, you need to implement a security function that will handle the validation of API keys. This function will be used as a dependency for the routes that require authentication. Here's an example:

from fastapi import HTTPException, status, Security, FastAPI
from fastapi.security import APIKeyHeader, APIKeyQuery

api_key_query = APIKeyQuery(name="api-key", auto_error=False)
api_key_header = APIKeyHeader(name="x-api-key", auto_error=False)

def get_api_key(
    api_key_query: str = Security(api_key_query),
    api_key_header: str = Security(api_key_header),
) -> str:
    """Retrieve and validate an API key from the query parameters or HTTP header.

    Args:
        api_key_query: The API key passed as a query parameter.
        api_key_header: The API key passed in the HTTP header.

    Returns:
        The validated API key.

    Raises:
        HTTPException: If the API key is invalid or missing.
    """
    if api_key_query in API_KEYS:
        return api_key_query
    if api_key_header in API_KEYS:
        return api_key_header
    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Invalid or missing API Key",
    )

In this example, we define instances of APIKeyQuery and APIKeyHeader classes, which represent the API key being passed as a query parameter or HTTP header, respectively. The get_api_key function takes these two parameters and validates the API key by checking if it exists in the API_KEYS list. If the key is valid, it is returned. Otherwise, an HTTPException is raised with a status code of 401 Unauthorized.

Step 3: Secure the Routes

Now that you have the API key security function, you can use it as a dependency for the routes that require authentication. Simply include the get_api_key function as a parameter in your route function. Here's an example:

app = FastAPI()

@app.get("/public")
def public():
    """A public endpoint that does not require any authentication."""
    return "Public Endpoint"

@app.get("/private")
def private(api_key: str = Security(get_api_key)):
    """A private endpoint that requires a valid API key to be provided."""
    return f"Private Endpoint. API Key: {api_key}"

In this example, the /public endpoint is accessible to everyone without authentication, while the /private endpoint requires a valid API key to be provided. By passing the get_api_key function as a security dependency, FastAPI will automatically validate the API key provided by the client before executing the route's function.

Step 4: Test and Documentation

Once you've implemented API Key authentication in your FastAPI application, it's crucial to test it to ensure everything is working as expected. Make requests to your protected endpoints with valid and invalid API keys to verify the behavior.

Additionally, FastAPI provides excellent documentation support for your API. When you run your FastAPI application and access the /docs endpoint, you'll see the security functionality reflected in the API documentation. Endpoints that require authentication will be marked accordingly, and you can use the Authorize button to include the API key in your requests.

API Docs

Complete Example

Here is a complete code example that demonstrates the implementation of API Key authentication in a FastAPI application.

from fastapi import HTTPException, status, Security, FastAPI
from fastapi.security import APIKeyHeader, APIKeyQuery

API_KEYS = [
    "9d207bf0-10f5-4d8f-a479-22ff5aeff8d1",
    "f47d4a2c-24cf-4745-937e-620a5963c0b8",
    "b7061546-75e8-444b-a2c4-f19655d07eb8",
]

api_key_query = APIKeyQuery(name="api-key", auto_error=False)
api_key_header = APIKeyHeader(name="x-api-key", auto_error=False)

def get_api_key(
    api_key_query: str = Security(api_key_query),
    api_key_header: str = Security(api_key_header),
) -> str:
    """Retrieve and validate an API key from the query parameters or HTTP header.

    Args:
        api_key_query: The API key passed as a query parameter.
        api_key_header: The API key passed in the HTTP header.

    Returns:
        The validated API key.

    Raises:
        HTTPException: If the API key is invalid or missing.
    """
    if api_key_query in API_KEYS:
        return api_key_query
    if api_key_header in API_KEYS:
        return api_key_header
    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Invalid or missing API Key",
    )

app = FastAPI()

@app.get("/public")
def public():
    """A public endpoint that does not require any authentication."""
    return "Public Endpoint"

@app.get("/private")
def private(api_key: str = Security(get_api_key)):
    """A private endpoint that requires a valid API key to be provided."""
    return f"Private Endpoint. API Key: {api_key}"

Conclusion

By adding API Key authentication to your FastAPI application, you can enhance its security and control access to your protected endpoints. This comprehensive guide has walked you through the process, from defining valid API keys to securing your routes and testing the implementation. Now you have the knowledge to incorporate API Key authentication into your FastAPI projects, ensuring secure and controlled API access.

If you have any questions or would like to discuss this topic further, feel free to connect with me on LinkedIn. I would be happy to hear your thoughts and continue the conversation! 😊