Add secure SECRET_KEY generation and improve key documentation

- Update config.py to auto-generate a secure SECRET_KEY if not provided
- Add warning log when using an auto-generated key
- Update README with clearer information about the two different keys
- Add detailed security notes explaining each key's purpose
This commit is contained in:
Automated Action 2025-05-27 18:57:18 +00:00
parent 90c1cdef34
commit 493289730d
2 changed files with 33 additions and 2 deletions

View File

@ -23,7 +23,7 @@ A FastAPI application that aggregates news from various sources using the Medias
## Requirements ## Requirements
- Python 3.8+ - Python 3.8+
- Mediastack API key - Mediastack API key (required for fetching news data)
## Setup ## Setup
@ -34,7 +34,12 @@ A FastAPI application that aggregates news from various sources using the Medias
``` ```
3. Set up environment variables: 3. Set up environment variables:
``` ```
# Required for fetching news from Mediastack API
MEDIASTACK_API_KEY=your_api_key_here MEDIASTACK_API_KEY=your_api_key_here
# Optional - For JWT authentication security
# If not set, a secure random key will be generated on startup
# but JWT tokens will be invalidated when the server restarts
SECRET_KEY=your_secret_key_here SECRET_KEY=your_secret_key_here
``` ```
@ -71,6 +76,14 @@ The API is documented with Swagger UI, available at `/docs` when the server is r
- `app/services`: Business logic services - `app/services`: Business logic services
- `migrations`: Database migrations - `migrations`: Database migrations
## Security Notes
The application uses two distinct keys for different purposes:
1. **Mediastack API Key**: Used to authenticate with the external Mediastack news API service. This key is required to fetch news data.
2. **Secret Key**: Used internally for JWT token generation and verification in the authentication system. If not provided via the SECRET_KEY environment variable, a secure random key will be generated automatically on each startup. Note that this means all active JWT tokens will be invalidated when the server restarts.
## Development ## Development
To run linting checks: To run linting checks:

View File

@ -1,9 +1,13 @@
from typing import List, Union from typing import List, Union
import logging
import secrets
from pathlib import Path from pathlib import Path
from pydantic import AnyHttpUrl, field_validator from pydantic import AnyHttpUrl, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings import BaseSettings, SettingsConfigDict
logger = logging.getLogger(__name__)
class Settings(BaseSettings): class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", case_sensitive=True) model_config = SettingsConfigDict(env_file=".env", case_sensitive=True)
@ -30,9 +34,23 @@ class Settings(BaseSettings):
MEDIASTACK_BASE_URL: str = "http://api.mediastack.com/v1" MEDIASTACK_BASE_URL: str = "http://api.mediastack.com/v1"
# Security # Security
SECRET_KEY: str = "your-secret-key-here" SECRET_KEY: str = ""
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8 # 8 days ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8 # 8 days
@field_validator("SECRET_KEY", mode="before")
@classmethod
def generate_secret_key_if_needed(cls, v: str) -> str:
"""Generate a secure secret key if none is provided."""
if not v:
generated_key = secrets.token_hex(32)
logger.warning(
"No SECRET_KEY provided. Using a randomly generated key. "
"This is OK for development but not recommended for production. "
"The authentication tokens will be invalidated on server restart."
)
return generated_key
return v
# Database # Database
DATABASE_PATH: Path = Path("/projects/newsaggregationservice-ks0ts2/app/storage/db/db.sqlite") DATABASE_PATH: Path = Path("/projects/newsaggregationservice-ks0ts2/app/storage/db/db.sqlite")