In this chapter, you’ll learn how to secure your services with an
authentication layer and implement authorization guards to
protect sensitive resources from nonprivileged users.
To achieve this, we’re going to explore various authentication
and authorization patterns then implement JWT and identity-
based authentication with role-based access control.
Authentication and Authorization
Before talking about authentication methods, let’s briefly clarify
that authentication and authorization are two separate
concepts that are often interchangeably used by mistake.
1
According to the OWASP definition:
Authentication is the process of verifying that an individual,
entity, or website is who or what it claims to be by
determining the validity of one or more authenticators (like
passwords, fingerprints, or security tokens) that are used to
back up this claim.
On the other hand, the National Institute of Standards and
Technology (NIST) defines authorization as:
A process for verifying that a requested action or service is
approved for a specific entity.
While authentication is about verifying the identity,
authorization focuses on verifying permissions of an identity to
access or mutate resources.
TIP
An analogy that might clarify this distinction is passing through passport control at
an airport. Authentication is like presenting your passport at immigration, while
authorization is like having the right visa to enter a country, specifying the duration
of your stay and permitted activities once you enter.
Let’s discuss authentication methods in more detail before
diving into authorization later in the chapter.
Authentication Methods
There are several authentication mechanisms that you can
implement in your GenAI services to secure them by identity
verification.
Depending on your security requirements, application
environment, budget, and project timelines, you may decide to
adopt one or more of the following authentication mechanisms:
Basic
Requiring the use of credentials such as username and
password to verify identity.
JSON Web Tokens (JWT)
Requiring the use of access tokens to verify identity. You
can think of access tokens like cinema tickets that dictate
whether you can access the screens and which screen
you’re visiting and where you’re sitting.
OAuth
Verifying an identity via an identity provider using the
OAuth2 standard.
Key-based
Using a private and public key pair to authenticate an
identity. Instead of tokens, the authorization server issues
a public key to the client and stores a copy of a linked
2
private key that it can use later for verification.
Figure 8-1 shows the data flow of the aforementioned
authentication methods in more detail.
Figure 8-1. Authentication methods
Being aware of authentication mechanisms, it can still be
challenging to decide on the method to adopt when addressing
your security requirements. To assist with the selection task,
Table 8-1 compares the aforementioned authentication
methods.
Table 8-1. Comparison of authentication methods
Type Benefits Limitations Use c
Basic Sends credentials in
Simplicity Pro
plain text
Fast to Int
implement no
Easy to en
understand
Token
Scalability Constant need to Sin
Decoupling regenerate short- an
facilitates lived tokens ap
implementation Complexity of Ap
of microservice client-side token req
architectures storage cu
Tokens can be Tokens can get au
signed and large, consuming flo
encrypted for excess bandwidth RE
higher security Stateless tokens
Highly can make multi-
customizable step applications
Self-contained hard to
reducing implement
Type Benefits Limitations Use c
database Client-side
round-trips misconfigurations
Can be passed can compromise
in HTTP tokens
headers
OAuth
Delegates Complex to Ap
authentication understand and req
to external implement da
providers Each identity ext
Based on a provider may ide
standard implement the pr
(OAuth2) and OAuth flow as
battle-tested for slightly Go
enterprise differently Mi
scenarios En
Access to ap
external tha
resources on SS
behalf of the ow
user pr
Type Benefits Limitations Use c
Key-based
Similar Managing and Sm
authentication keeping private ap
mechanism to keys secure can Ap
Secure Shell be complex wi
(SSH) access Compromised int
keys can create en
security risks
Scalability issues
You should now feel confident in deciding the appropriate
authentication mechanism to adopt. In the next section, you’re
going to implement basic, JWT, and OAuth authentication for
your GenAI to fully understand the underlying components and
their interactions.
Basic Authentication
In basic authentication, the client provides a username and
password when making a request to access resources from the
server. It is the simplest technique as it won’t require cookies,
session identifiers, or any login forms to be implemented.
Because of its simplicity, basic authentication is ideal for
sandbox environments and when prototyping. However, avoid
using it in production environments as it transmits usernames
and passwords in plain text on every request, making it highly
vulnerable to interception attacks.
To perform an authenticated request via basic authentication,
you must add an Authorization header with a value of
Basic <credentials> for the server to successfully
authenticate it. The <credentials> value must be a Base64
encoding of the username and password joined by a single
colon (i.e., [Link](ali:secretpassword) .
In FastAPI, you can protect an endpoint with basic
authentication, as shown in Example 8-1.
Example 8-1. Implementing basic authentication in FastAPI
import secrets
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPExcepti
from [Link] import HTTPBasic, HTTPBasic
app = FastAPI()
security = HTTPBasic()
username_bytes = b"ali"
password_bytes = b"secretpassword"
def authenticate_user(
credentials: Annotated[HTTPBasicCredentials,
) -> str:
is_correct_username = secrets.compare_digest
[Link]("UTF-8"), use
)
is_correct_password = secrets.compare_digest
[Link]("UTF-8"), pas
)
if not (is_correct_username and is_correct_pa
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORI
detail="Incorrect credentials",
headers={"WWW-Authenticate": "Basic"}
)
return [Link]
AuthenticatedUserDep = Annotated[str, Depends(aut
@[Link]("/users/me")
def get_current_user_controller(username: Authent
return {"message": f"Current user is {usernam