FastAPI helpers for Better Auth JWT verification
Project description
fastapi-betterauth
A simple FastAPI dependency to securely validate JSON Web Tokens (JWTs) issued by Better Auth.
If your frontend logs users in with Better Auth and sends their tokens to your FastAPI backend, this library will verify those tokens and extract the user's details for you.
Installation
pip install "fastapi-betterauth"
The package requires Python 3.10+
Usage
Enable the Better Auth JWT plugin on your Better Auth server:
import { betterAuth } from "better-auth";
import { jwt } from "better-auth/plugins";
export const auth = betterAuth({
plugins: [jwt()],
});
Enable the Better Auth JWT client plugin where your frontend requests tokens:
import { jwtClient } from "better-auth/client/plugins";
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
plugins: [jwtClient()],
});
Create a FastAPI dependency with your Better Auth base URL:
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi_betterauth import BetterAuth, User
app = FastAPI()
better_auth = BetterAuth("http://localhost:3000")
@app.get("/me")
def me(user: Annotated[User, Depends(better_auth)]):
return user
Send the JWT to FastAPI as a bearer token:
const { data } = await authClient.token();
const response = await fetch("http://127.0.0.1:8000/me", {
headers: {
Authorization: `Bearer ${data.token}`,
},
});
If your Better Auth JWKS endpoint is not /api/auth/jwks, pass a custom path:
better_auth = BetterAuth(
"https://auth.example.com",
auth_path="/custom/auth/jwks",
)
For optional authentication, set auto_error=False. Missing credentials return
None instead of raising a 401 response. Invalid bearer tokens still raise a
401 response:
optional_better_auth = BetterAuth(
"https://auth.example.com",
auto_error=False,
)
API Table
BetterAuth
| Parameter | Type | Default | Description |
|---|---|---|---|
base_url |
str |
Required | Public base URL of your Better Auth server. It is also used as the expected JWT issuer and audience. |
auth_path |
str |
"/api/auth/jwks" |
Path to the Better Auth JWKS endpoint. |
cache_keys |
bool |
False |
Passed to jwt.PyJWKClient to cache individual signing keys. |
max_cached_keys |
int |
16 |
Maximum number of signing keys to cache when cache_keys=True. |
cache_jwk_set |
bool |
True |
Passed to jwt.PyJWKClient to cache the JWKS response. |
lifespan |
float |
300 |
JWKS cache lifespan in seconds. |
headers |
dict[str, Any] | None |
None |
Extra headers sent when fetching the JWKS. |
timeout |
float |
30 |
Timeout in seconds for fetching the JWKS. |
ssl_context |
SSLContext | None |
None |
Custom SSL context for the JWKS request. |
auto_error |
bool |
True |
When True, missing or invalid bearer tokens raise 401 Not authenticated. When False, missing credentials return None; invalid bearer tokens still raise 401 Not authenticated. |
Methods and Types
| Name | Type | Description |
|---|---|---|
BetterAuth.fetch_token(token) |
Method | Verifies a raw JWT string and returns decoded claims as User. Raises TokenValidationError when validation fails. |
BetterAuth.make_not_authenticated_error() |
Method | Builds the FastAPI HTTPException used for 401 Not authenticated responses. |
User |
TypedDict |
Common Better Auth JWT claims, including id, sub, email, name, image, emailVerified, iat, exp, iss, aud, createdAt, and updatedAt. Extra claims may still be present at runtime. |
TokenValidationError |
Exception | Raised by fetch_token when a token cannot be validated. |
Guide
What JWKS is
JWKS means JSON Web Key Set. It is a JSON document that contains public keys for verifying JWT signatures.
JWT authentication usually has two sides:
- Better Auth signs a token with a private key.
- FastAPI verifies the token with the matching public key.
FastAPI does not need the private key. It only needs to know where to find the public keys. Better Auth exposes those public keys through its JWKS endpoint, which defaults to:
<better-auth-base-url>/api/auth/jwks
For example, if Better Auth runs at http://localhost:3000, the JWKS endpoint is:
http://localhost:3000/api/auth/jwks
How it integrates with FastAPI
fastapi-betterauth wraps this verification flow in a FastAPI dependency:
- The client signs in through Better Auth.
- The frontend asks Better Auth for a JWT with
authClient.token(). - The frontend sends that token to FastAPI in the
Authorizationheader. BetterAuthreads the bearer token from the request.BetterAuthdownloads the signing key from the JWKS endpoint when needed.- The JWT is verified with
EdDSA. - The token
issandaudclaims must match thebase_urlpassed toBetterAuth. - Your route receives the decoded claims as a normal dependency value.
That means your FastAPI routes can stay small:
@app.get("/private")
def private_route(user: Annotated[User, Depends(better_auth)]):
return {"user_id": user["id"], "email": user["email"]}
If the request has no bearer token, or the token is expired, malformed, signed
with the wrong key, or issued for a different Better Auth base URL, the dependency
returns 401 Not authenticated.
Project details
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
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_betterauth-0.2.6.tar.gz.
File metadata
- Download URL: fastapi_betterauth-0.2.6.tar.gz
- Upload date:
- Size: 5.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4127740cb0af85cd1de8dff91e8a7a6e6bec8150ad88aeea469468627c9c863a
|
|
| MD5 |
309b2fd66eea1c57f3ba69cc741900c8
|
|
| BLAKE2b-256 |
fe3d9a8e7a649d30439b9a58f1baba4661f31b4f433c3839363f9c16e1d1158f
|
File details
Details for the file fastapi_betterauth-0.2.6-py3-none-any.whl.
File metadata
- Download URL: fastapi_betterauth-0.2.6-py3-none-any.whl
- Upload date:
- Size: 5.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8550002555d384568f9dcfc93dd4a9e59283fdae68cb00d0e05b77c0ccd59c54
|
|
| MD5 |
fe727b83c86bb3ce8dec21a6e89f05b0
|
|
| BLAKE2b-256 |
a60f40d8282aa578325cbab939cc0bab603f661c353a62c4b9e3cb3e2bad344d
|