How to Manage JWT Settings in FastAPI: Secret Keys and Token Expiration

Manage JWT settings in the fastapi-boilerplate by configuring the CryptSettings class in src/app/core/config.py via environment variables for the secret key, algorithm, and token lifetimes.

The benavlabs/fastapi-boilerplate repository centralizes all cryptographic configuration in a dedicated settings group, making it straightforward to manage JWT settings like secret keys and expiration times without modifying application logic. This approach leverages Pydantic Settings to load sensitive values from environment variables, ensuring your secret key never resides in source control.

Where JWT Settings Are Stored

All JWT configuration lives in the CryptSettings class defined in src/app/core/config.py. This class is aggregated into the global settings object when the application starts.

The following parameters control token behavior:

  • SECRET_KEY – A SecretStr field that defaults to "secret-key" but should be overridden via the SECRET_KEY environment variable.
  • ALGORITHM – The signing algorithm (default HS256).
  • ACCESS_TOKEN_EXPIRE_MINUTES – Lifetime of access tokens (default 30 minutes).
  • REFRESH_TOKEN_EXPIRE_DAYS – Lifetime of refresh tokens (default 7 days).

These values are referenced throughout the authentication layer to ensure consistent token generation and validation.

How to Configure JWT Parameters via Environment Variables

To manage JWT settings securely, define them in a .env file at the project root or export them directly in your deployment environment.


# .env

SECRET_KEY=MyVerySecretKey123!
ACCESS_TOKEN_EXPIRE_MINUTES=45
REFRESH_TOKEN_EXPIRE_DAYS=10
ALGORITHM=HS256

The Settings object automatically reads these variables via pydantic-settings. After modifying the environment, restart the application to load the new values. All JWT creation and verification logic in src/app/core/security.py will immediately use the updated secret key and lifetimes without requiring code changes.

How JWT Settings Are Used in Token Operations

The src/app/core/security.py module consumes the global settings to implement token lifecycle management.

Token Creation

The create_access_token function uses settings.ACCESS_TOKEN_EXPIRE_MINUTES to compute the exp claim:

from datetime import timedelta
from src.app.core.security import create_access_token, settings

payload = {"sub": "alice"}
access_token = await create_access_token(
    data=payload,
    expires_delta=timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
)

Similarly, create_refresh_token references settings.REFRESH_TOKEN_EXPIRE_DAYS for extended lifetimes.

Token Verification

The verify_token function decodes tokens using the same secret key and algorithm defined in CryptSettings, ensuring that only tokens issued by the application are accepted.

Login Route Integration

The login endpoint in src/app/api/v1/login.py demonstrates practical usage by reading ACCESS_TOKEN_EXPIRE_MINUTES to construct token expiration deltas and setting refresh cookie max_age based on REFRESH_TOKEN_EXPIRE_DAYS.

Practical Configuration Examples

Changing the Algorithm

While HS256 is the default, you can upgrade to HS512 for stronger signatures:

ALGORITHM=HS512

Creating Tokens with Custom Expiration

Override the default expiration programmatically when needed:

from datetime import timedelta

# Short-lived token for sensitive operations

token = await create_access_token(
    data={"sub": "user@example.com"},
    expires_delta=timedelta(minutes=5)
)

Refreshing Tokens

The refresh flow uses the configured expiration settings automatically:

from fastapi import Request, Depends
from src.app.core.security import verify_token, TokenType, create_access_token
from src.app.core.db.database import async_get_db

async def refresh(request: Request, db=Depends(async_get_db)):
    refresh_token = request.cookies.get("refresh_token")
    user_data = await verify_token(refresh_token, TokenType.REFRESH, db)
    
    new_access = await create_access_token({"sub": user_data.username_or_email})
    return {"access_token": new_access, "token_type": "bearer"}

Summary

  • Centralized Configuration: All JWT settings reside in CryptSettings within src/app/core/config.py, aggregated into a global settings object.
  • Environment-Driven: Manage the secret key, algorithm, and token lifetimes via environment variables (SECRET_KEY, ACCESS_TOKEN_EXPIRE_MINUTES, REFRESH_TOKEN_EXPIRE_DAYS) rather than hard-coding values.
  • Automatic Integration: The src/app/core/security.py module automatically consumes these settings for token creation and verification, while src/app/api/v1/login.py demonstrates practical usage in authentication flows.
  • Security Best Practice: Never commit secrets to source control; use .env files or deployment environment variables to manage sensitive JWT configuration.

Frequently Asked Questions

How do I rotate the JWT secret key in production?

To rotate the secret key, update the SECRET_KEY environment variable in your deployment platform or .env file and restart the application. Note that changing the secret will invalidate all existing tokens issued with the previous key, forcing users to re-authenticate. Plan rotations during maintenance windows to minimize disruption.

Can I use asymmetric algorithms like RS256 instead of HS256?

Yes, you can change the algorithm by setting the ALGORITHM environment variable to RS256 and providing the corresponding private/public key pair. However, you must modify the CryptSettings class in src/app/core/config.py to handle the additional key variables (e.g., PRIVATE_KEY and PUBLIC_KEY) and update the security.py functions to use the appropriate key for signing versus verification.

Why are refresh tokens configured in days while access tokens use minutes?

This distinction reflects standard security practices for token lifetimes. Access tokens are short-lived (minutes) to minimize the window of exposure if they are intercepted, while refresh tokens are long-lived (days) to provide a better user experience by reducing the frequency of full re-authentication. You can adjust these values via ACCESS_TOKEN_EXPIRE_MINUTES and REFRESH_TOKEN_EXPIRE_DAYS to balance security requirements against user convenience.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →