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
SecretStrfield that defaults to"secret-key"but should be overridden via theSECRET_KEYenvironment 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
CryptSettingswithinsrc/app/core/config.py, aggregated into a globalsettingsobject. - 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.pymodule automatically consumes these settings for token creation and verification, whilesrc/app/api/v1/login.pydemonstrates practical usage in authentication flows. - Security Best Practice: Never commit secrets to source control; use
.envfiles 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →