Skip to main content

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:

  1. Better Auth signs a token with a private key.
  2. 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:

  1. The client signs in through Better Auth.
  2. The frontend asks Better Auth for a JWT with authClient.token().
  3. The frontend sends that token to FastAPI in the Authorization header.
  4. BetterAuth reads the bearer token from the request.
  5. BetterAuth downloads the signing key from the JWKS endpoint when needed.
  6. The JWT is verified with EdDSA.
  7. The token iss and aud claims must match the base_url passed to BetterAuth.
  8. 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

fastapi_betterauth-0.2.6.tar.gz (5.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_betterauth-0.2.6-py3-none-any.whl (5.7 kB view details)

Uploaded Python 3

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

Hashes for fastapi_betterauth-0.2.6.tar.gz
Algorithm Hash digest
SHA256 4127740cb0af85cd1de8dff91e8a7a6e6bec8150ad88aeea469468627c9c863a
MD5 309b2fd66eea1c57f3ba69cc741900c8
BLAKE2b-256 fe3d9a8e7a649d30439b9a58f1baba4661f31b4f433c3839363f9c16e1d1158f

See more details on using hashes here.

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

Hashes for fastapi_betterauth-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 8550002555d384568f9dcfc93dd4a9e59283fdae68cb00d0e05b77c0ccd59c54
MD5 fe727b83c86bb3ce8dec21a6e89f05b0
BLAKE2b-256 a60f40d8282aa578325cbab939cc0bab603f661c353a62c4b9e3cb3e2bad344d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page