JWT authentication in FastAPI with ease
Project description
FastAPI JWT Auth
FastAPI JWT Auth is a lightweight library designed to simplify the integration of JWT authentication into FastAPI applications. By strictly adhering to FastAPI conventions, it provides a seamless and straightforward authentication setup process. The library aims for 100% test coverage.
Installing
pip install fastapi-jwt-auth3
NOTE: There are others who have written similar libraries with identical names. As an homage to the libraries that came before, I have decided to name this library fastapi-jwt-auth3
.
How To Use
This is an example single file implementation, let's name it example.py
.
In order for this example to run, I took the liberty to use the Faker
library to generate fake data. You can install it by running pip install faker
.
__all__ = ["app"]
import uuid
from fastapi import FastAPI, Depends, HTTPException
from faker import Faker
from jwcrypto import jwk
from pydantic import BaseModel, ConfigDict, EmailStr
from fastapi_jwt_auth3.jwtauth import FastAPIJWTAuth, KeypairGenerator, JWTPresetClaims, generate_jwt_token
# Initialize the Faker instance to generate fake data
fake = Faker()
# Define the token claims to be projected to when decoding JWT tokens
class TokenClaims(BaseModel):
model_config = ConfigDict(extra="forbid")
name: str
email: EmailStr
iss: str
aud: str
exp: int
sub: str
iat: int
jti: str
# Payload for our logins
class LoginIn(BaseModel):
username: str
password: str
app = FastAPI(title="FastAPI JWT Auth Example")
# For the purpose of this example, we will generate a new RSA keypair
private_key, public_key = KeypairGenerator.generate_rsa_keypair()
# Create a JWK key from the public key
jwk_key = jwk.JWK.from_pem(public_key.encode("utf-8"))
public_key_id = jwk_key.get("kid")
"""
Initialize the FastAPIJWTAuth instance with an RSA algorithm. We need to provide a set of private and public key.
"""
jwt_auth = FastAPIJWTAuth(
algorithm="RS256",
base_url="http://localhost:8000",
secret_key=private_key,
public_key=public_key,
public_key_id=public_key_id,
issuer="https://localhost:8000",
audience="https://localhost:8000",
expiry=60 * 15,
refresh_token_expiry=60 * 60 * 24 * 7,
leeway=0,
project_to=TokenClaims,
)
"""
Initialize the FastAPIJWTAuth instance with a FastAPI app. This will add a route at:
[GET] /.well-known/jwks.json
This route will return the public key in JWK format for consumers to verify the JWT token.
"""
jwt_auth.init_app(app)
@app.get("/protected")
async def protected_route(claims: TokenClaims = Depends(jwt_auth)):
return {"message": f"Hello, {claims.name}!"}
@app.post("/login")
async def login(payload: LoginIn):
if payload.username != "username" or payload.password != "password":
raise HTTPException(status_code=401, detail="Invalid credentials")
preset_claims = JWTPresetClaims.factory(
issuer=jwt_auth.issuer, audience=jwt_auth.audience, expiry=jwt_auth.expiry, subject=str(uuid.uuid4())
)
claims = {"name": fake.name(), "email": fake.email()}
token = generate_jwt_token(
header=jwt_auth.header, secret_key=jwt_auth.secret_key, preset_claims=preset_claims, claims=claims
)
# This is optional but good practice
refresh_token = jwt_auth.generate_refresh_token(access_token=token)
return {"access_token": token, "refresh_token": refresh_token}
We can run the example above with uvicorn
. You can install with pip install uvicorn
.
uvicorn example:app --reload
Handling Refresh Tokens
As you can see in the examples above, you can optionally use a refresh_token
. What this library does not cover is the handling of the refresh_token
. You can implement your own logic to handle the refresh token. In terms of best practice, it's prudent to set a short expiry time for the access_token
like 15 minutes and a longer expiry time for the refresh_token
like 7 days.
Every refresh_token
issued by the library will have the following claims attributed to it based on the access token. An example is below:
{
"iss": "https://localhost:8000",
"aud": "https://localhost:8000",
"exp": 1719100800,
"kid": "U790ZCw3aTvd3Z-Nzm5z2CdW7QFjlGk-HchE3EXhfR8",
"jku": "http://localhost:8000/.well-known/jwks.json",
"sub": "cbb6aa8b-a602-43fa-a578-76db183e3b2b",
"access_token_jti": "84db4b73-df2a-4690-802c-3c55247a6631",
"access_token_iat": 1717933045
}
Refresh token claims will always have the access_token_jti
and access_token_iat
claims. These claims are used to verify the integrity of the access token. If the access token is revoked, the refresh token will be invalidated when you set it up as such with your own logic.
Generating Keys
The library comes with a CLI tool called keygen
to help you create keys for your application.
To generate a new RSA keypair, you can run the following command:
keygen --algorithm=RS256
The private/public keys will be saved at the current working directory with the following filenames:
private_key.pem
public_key.pem
For a list of the available algorithms supported, you can go here:
https://pyjwt.readthedocs.io/en/stable/algorithms.html
Development
This project uses rye
to build, test and publish the package. More about rye
can be found in the link below:
Please install rye
first before continuing.
Environment Setup
After rye
is installed and available in your path, you can do the following to set up the environment:
git clone git@github.com:tistaharahap/fastapi-jwt-auth.git
cd fastapi-jwt-auth
rye sync
Testing
To run the tests, you can use the following command:
rye run test
When the command is run, coverage reports will be generated in these files and directory:
htmlcov/
coverage.json
coverage.xml
Coverage report can be viewed as an HTML file by opening htmlcov/index.html
in your browser.
In addition, coverage report is uploaded to Codecov
, link here. A Github action in the repository uploads the coverage report to Codecov
automatically after successful tests.
This project aims to have 100% test coverage.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for fastapi_jwt_auth3-0.3.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b85742d2eb4238f788d0a9551bc1d77f3bb888d8b9b0c4d6575527563f9a5eab |
|
MD5 | a0404810fd10ae807db9c0f2a6cb413c |
|
BLAKE2b-256 | 6cde883ec875e721828e3527e01432eb56ed185f1c0a47bbcad8f5b00829038c |