Metadata-Version: 2.4
Name: django-project-core-settings
Version: 1.0.2
Summary: Secure, modular Django project foundation with environment-aware settings and optional session/API authentication.
Author: Wilfred Pine
License: MIT
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: Django<6.2,>=6.1
Requires-Dist: argon2-cffi<26,>=23.1
Requires-Dist: python-dotenv<2,>=1.2.3
Requires-Dist: whitenoise<7,>=6.12
Provides-Extra: api
Requires-Dist: djangorestframework<3.19,>=3.18; extra == "api"
Requires-Dist: djangorestframework-simplejwt<6,>=5.5.1; extra == "api"
Provides-Extra: redis
Requires-Dist: django-redis<8,>=7; extra == "redis"
Provides-Extra: dev
Requires-Dist: build<2,>=1.2; extra == "dev"
Requires-Dist: pip<27,>=26.2; extra == "dev"
Requires-Dist: pip-audit<3,>=2.10; extra == "dev"
Requires-Dist: pytest<10,>=9.0.3; extra == "dev"
Requires-Dist: pytest-django<5,>=4.11; extra == "dev"
Requires-Dist: ruff<0.13,>=0.12; extra == "dev"
Requires-Dist: setuptools>=75; extra == "dev"
Requires-Dist: twine<8,>=6; extra == "dev"
Requires-Dist: wheel>=0.45; extra == "dev"
Provides-Extra: full
Requires-Dist: djangorestframework<3.19,>=3.18; extra == "full"
Requires-Dist: djangorestframework-simplejwt<6,>=5.5.1; extra == "full"
Requires-Dist: django-redis<8,>=7; extra == "full"

# django-project-core-settings

Secure, environment-aware Django project defaults with optional form/session and API/JWT authentication. The package is a foundation: your project owns its user model, URLs, templates, deployment platform, and operational policy.

## Start quickly

```powershell
py -m venv .venv
.\.venv\Scripts\Activate.ps1
py -m pip install "django-project-core-settings"
django-admin startproject config .
```

Import `django_project_core_settings` in the project settings module, add a project user app, and include `django_project_core_settings.auth.urls`. For the full beginner-to-production walkthrough, see [docs/00_START_HERE.md](docs/00_START_HERE.md). For API/JWT install `[api]`, set `CORE_ENABLE_API=true`, and include `django_project_core_settings.auth.api_urls`.

## Guided documentation

- [Start here](docs/00_START_HERE.md) — guided installation and configuration path
- [API/JWT](docs/09_API_JWT.md), [production setup](docs/17_PRODUCTION_SETUP.md), and [security testing](docs/19_SECURITY_TESTING.md)
- Verified development projects: [session](examples/session_project) and [API](examples/api_project)
- Deployment reference: [examples/production_project](examples/production_project)

Version 1.0.2 requires Python 3.12+ and Django 6.1.x. The optional API extra
requires Django REST framework 3.18.x and SimpleJWT 5.5.x; the Redis extra
requires django-redis 7.x. Documentation is not a production-readiness
certification; validate your application, infrastructure, secrets, TLS
termination, backups, and monitoring.

Release validation runs `scripts/verify_release_artifacts.py` against built
wheel and sdist files; it creates clean environments, installs the base and
full extras, and smoke-tests API/JWT routes without an editable install.

---

**One package. Secure defaults. Minimal project settings.**

This is the clean-room consolidation of the two supplied packages:

- `django-project-core-settings`
- `django-did-auth`

The new design keeps the useful behavior from both packages but removes the hard coupling that made the original setup fragile.

## What changed

### 1. One distribution

Install one package:

```bash
python -m pip install "django-project-core-settings"
```

For API/JWT support:

```bash
python -m pip install "django-project-core-settings[api]"
```

For API + CORS + Redis:

```bash
python -m pip install "django-project-core-settings[full]"
```

### 2. Environment selection is automatic

Set only:

```env
DJANGO_ENV=dev
```

Supported values:

- `dev`
- `prod`
- `test`
- `local` is accepted as a backwards-compatible alias for `dev`

### 3. Minimal `settings.py`

```python
from django_project_core_settings import *

INSTALLED_APPS += ["users"]

AUTH_USER_MODEL = "users.CustomUser"

ROOT_URLCONF = "config.urls"
WSGI_APPLICATION = "config.wsgi.application"
ASGI_APPLICATION = "config.asgi.application"
```

The package supplies the security baseline. Project code adds only project-specific settings.

### 4. Form/session authentication

Add:

```python
path("auth/", include("django_project_core_settings.auth.urls"))
```

The package provides:

- registration
- email verification
- login/logout
- password reset
- password change
- email authentication backend
- role-aware redirects
- role-required decorator
- cache-backed rate limiting
- audit logging

Browser session logout is `POST /auth/logout/` only and requires Django's CSRF
token. Package templates render a sign-out form; do not link to the logout URL.

### 5. API/JWT authentication

Set:

```env
CORE_ENABLE_API=true
```

Install the API extra and include:

```python
path("api/auth/", include("django_project_core_settings.auth.api_urls"))
```

The API provides:

- login
- logout
- registration
- activation
- password reset
- password change
- profile
- role permission example
- JWT access/refresh tokens
- refresh-token rotation and blacklist support

The refresh endpoint is `POST /api/auth/refresh/` and accepts a `refresh`
token. Rotation blacklists the submitted token and returns a replacement.

## Security baseline

The package uses Django 6.1 security facilities rather than old third-party replacements wherever possible.

Defaults include:

- Argon2 first password hasher
- CSRF middleware
- secure session cookies in production
- secure CSRF cookies in production
- `HttpOnly` session cookie
- `SameSite=Lax`
- clickjacking protection
- content-type sniffing protection
- strict referrer policy
- Cross-Origin Opener Policy
- HTTPS redirect in production
- HSTS in production
- built-in Django CSP middleware
- CSP nonce support instead of `unsafe-inline`
- upload size limits
- environment-based secrets
- generic password-reset responses
- no public role assignment during registration
- cache-backed authentication rate limits
- generic API authentication failures
- JWT signing key validation through configuration
- production secret key requirement

Django 6.1 has built-in CSP support, so this package does not depend on the older `django-csp` approach.

## Important design rule

The package is a **foundation**, not a replacement for project settings.

Project settings can override any normal Django setting after the import:

```python
from django_project_core_settings import *

DEBUG = False
ALLOWED_HOSTS = ["example.com"]
LOGIN_REDIRECT_URL = "/dashboard/"
```

For environment configuration, use `.env`:

```env
ALLOWED_HOSTS=example.com,www.example.com
CSRF_TRUSTED_ORIGINS=https://example.com
```

Process environment variables take precedence over `.env`.

## Why this architecture is safer

The supplied packages had several coupling and correctness problems:

- the settings package imported the authentication package directly;
- REST settings imported Redis-dependent authentication code during settings loading;
- Redis availability was checked during import;
- `local` and `prod` behavior overlapped;
- CORS was configured as allow-all in local settings;
- CSP used `unsafe-inline`;
- the authentication package accepted a role from public API registration;
- API exception handlers returned internal exception details;
- API refresh logic depended on `request.user` even though refresh endpoints are normally unauthenticated;
- the old activation flow required a custom `activation_token_created` field on the project user model;
- `django-ratelimit` and Axes were coupled to the settings package even when a project did not need the full API/auth stack.

The new package avoids those startup dependencies and makes API, CORS, and Redis optional capabilities.

## Configuration reference

| Variable | Default | Production behavior |
|---|---|---|
| `DJANGO_ENV` | `dev` | use `prod` |
| `SECRET_KEY` | generated for dev/test | required |
| `DEBUG` | derived | `False` |
| `ALLOWED_HOSTS` | localhost in dev | set explicitly |
| `CORE_PUBLIC_ORIGIN` | `http://localhost` outside prod | required HTTPS public origin for activation/reset email links |
| `CSRF_TRUSTED_ORIGINS` | empty | set for trusted HTTPS origins |
| `CORE_ENABLE_API` | `false` | enable when using API |
| `CORE_ENABLE_CORS` | `false` | enable only when needed |
| `CORE_ENABLE_REDIS` | `false` | required when production authentication rate limiting is enabled |
| `CORE_REDIS_REQUIRED` | derived | fail cache operations when production rate limiting is enabled |
| `AUTH_VERIFY_HOURS` | `24` | override if required |
| `AUTH_RESET_SECONDS` | `3600` | override if required |
| `AUTH_LOGIN_RATE` | `10/m` | login requests per IP |
| `AUTH_REGISTER_RATE` | `5/m` | registration requests per IP |
| `AUTH_PASSWORD_RESET_RATE` | `5/m` | password-reset requests per email |
| `AUTH_PASSWORD_CHANGE_RATE` | `5/m` | password-change requests per user |
| `AUTH_ROLE_REDIRECTS` | empty | `admin=/admin/,user=/dashboard/` style |
| `AUTH_DEFAULT_ROLE` | `user` | project override |
| `AUTH_DENY_BEHAVIOR` | `redirect` | use `forbidden` when preferred |
| `JWT_ACCESS_MINUTES` | `15` | project override |
| `JWT_REFRESH_DAYS` | `1` | project override |

Argon2 is a base dependency because it is the package's default password
hasher. Authentication rate limiting deliberately refuses a production
configuration without Redis enabled; local-memory counters cannot protect a
multi-worker deployment. Redis must be reachable at runtime when required.

### Authentication-rate setting rename

`AUTH_RESET_RATE` and `AUTH_CHANGE_PASSWORD_RATE` have been removed. Use
`AUTH_PASSWORD_RESET_RATE` and `AUTH_PASSWORD_CHANGE_RATE` instead. The old
names are intentionally not aliases, so configuration errors are not hidden by
unclear precedence.

## User model contract

The package does not ship a user model. The project owns it.

For email authentication, the user model must expose an `email` field.

If role-based behavior is needed, add a `role` field or change:

```env
AUTH_ROLE_FIELD=your_role_field
```

Do **not** expose the role as a public registration input.

## Production deployment

Production startup requires an injected `SECRET_KEY`, explicit non-wildcard
`ALLOWED_HOSTS`, an HTTPS `CORE_PUBLIC_ORIGIN`, SMTP configuration, Redis for
authentication throttles, and a non-SQLite database engine/name. Use a
project-provided database driver (for example
`psycopg` for PostgreSQL), run `python manage.py migrate` including the
SimpleJWT blacklist migrations, and keep database/cache storage persistent.

`CORE_PUBLIC_ORIGIN` is the canonical scheme and host used for activation and
password-reset email links (for example, `https://accounts.example.com`). It
must not contain a path, query, or fragment. These links never use the request
`Host` header. Configure the origin for the externally reachable TLS endpoint;
`CORE_TRUST_PROXY` and `CORE_TRUSTED_PROXY_CIDRS` enable the package's validated
immediate-proxy middleware; forwarded identity is accepted only from a peer in the
configured CIDRs and does not alter email-link construction. DRF `NUM_PROXIES`
defaults to `0`.

`JWT_SIGNING_KEY` is optional. When omitted, JWTs use `SECRET_KEY`; when set,
it is an independent signing key and must be rotated through your secret
manager with an application rollout. Password reset/change revokes existing
JWT credentials, so clients must sign in again.

TLS should terminate at Django or a controlled proxy. Set `CORE_TRUST_PROXY=true`
only with explicit `CORE_TRUSTED_PROXY_CIDRS` for a controlled immediate proxy.
Production trusted
origins and CORS origins must be HTTPS URLs. HSTS includeSubDomains and preload
are opt-in; preload requires includeSubDomains and one-year HSTS. Collect JSON audit logs from
standard output with your platform's log collector, test health endpoints in
the host project, and define project rollback/backup policy.

## Runnable examples

Both [session_project](examples/session_project/) and
[api_project](examples/api_project/) include `manage.py`, a custom user app,
migrations, and `.env.example`. From either directory, install its
`requirements.txt`, copy `.env.example` to `.env`, then run `python manage.py
migrate` and `python manage.py runserver`.

See [deployment guidance](docs/DEPLOYMENT.md) for production prerequisites,
migrations, logging, and rollback responsibilities.

Example:

```python
class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(unique=True)
    role = models.CharField(max_length=30, default="user")

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []
```

## Updating the framework

Projects depend on the package, not copied framework code:

```bash
python -m pip install --upgrade django-project-core-settings
```

A framework security fix can therefore be shipped through the package without copying settings/authentication files into every project.

## Verification

Run:

```bash
python manage.py check
python manage.py check --deploy
python manage.py test
```

For API projects:

```bash
python manage.py migrate
python manage.py check
python manage.py check --deploy
python manage.py test
```

## License

MIT
