Metadata-Version: 2.5
Name: ybz-dj-auth
Version: 0.2.2
Summary: Reusable Django app providing production-ready authentication: email login, passkeys, TOTP, social auth.
Project-URL: Repository, https://github.com/damycra/dj-auth
License: MIT
Requires-Python: >=3.13
Requires-Dist: django-allauth[mfa]>=65.0
Requires-Dist: django>=5.2
Provides-Extra: dev
Requires-Dist: django-allauth[socialaccount]>=65.0; extra == 'dev'
Requires-Dist: pytest-django>=4.9; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: python-decouple>=3.8; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Requires-Dist: tox>=4.23; extra == 'dev'
Requires-Dist: whitenoise>=6.9; extra == 'dev'
Description-Content-Type: text/markdown

# dj-auth

A reusable Django app providing production-ready authentication out of the box:

- **Email login** — email/password auth via django-allauth, no username required
- **Passkeys** — WebAuthn/FIDO2 passkey login (biometrics, hardware keys)
- **TOTP / 2FA** — authenticator app support with recovery codes
- **Social auth** — Google and GitHub OAuth preconfigured, others easy to add
- **Polished UI** — Tailwind CSS templates for login, signup, MFA settings, and more
- **Zero models** — no migrations; drop it into any project without touching your schema
- **System checks** — warns you at startup if required dependencies are misconfigured

## Quick Start

### 1. Install

```bash
# From PyPI (published as "ybz-dj-auth"; the importable package is still dj_auth)
pip install ybz-dj-auth

# Or install directly from GitHub:

# Latest commit on main
pip install git+https://github.com/damycra/dj-auth.git

# Specific tagged release (recommended for reproducible builds)
pip install git+https://github.com/damycra/dj-auth.git@v0.1.0

# Or download the wheel from a GitHub Release and install locally
pip install ybz_dj_auth-0.2.1-py3-none-any.whl
```

### 2. Add to INSTALLED_APPS

> **Important:** `dj_auth` must appear **before** `allauth` and all `allauth.*` entries.
> Django's template loader searches apps in order — if allauth comes first, its own
> unstyled built-in templates shadow dj_auth's styled overrides. `manage.py check`
> will warn you (`dj_auth.W004`) if the ordering is wrong.

```python
INSTALLED_APPS = [
    # ... Django built-ins ...
    "django.contrib.sites",       # required by allauth

    "dj_auth",                    # must come before allauth

    "allauth",
    "allauth.account",
    "allauth.socialaccount",      # optional: social login
    "allauth.mfa",                # optional: MFA / passkeys

    # ... your apps ...
]
```

> `allauth.socialaccount` and `allauth.mfa` are genuinely optional: the login
> and signup pages detect whether they are installed and simply omit the
> social-login buttons / passkey button when they're not. `manage.py check`
> emits a warning (`dj_auth.W001` / `dj_auth.W002`) so you know the feature
> is unavailable.

### 3. Configure MIDDLEWARE

Add `AccountMiddleware` after `SessionMiddleware`:

```python
MIDDLEWARE = [
    ...
    "django.contrib.sessions.middleware.SessionMiddleware",
    ...
    "allauth.account.middleware.AccountMiddleware",
]
```

### 4. Configure AUTHENTICATION_BACKENDS

```python
AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",           # keep for admin
    "allauth.account.auth_backends.AuthenticationBackend", # required by allauth
]
```

### 5. Include URLs

```python
# config/urls.py
from django.urls import include, path

urlpatterns = [
    path("accounts/", include("dj_auth.urls")),
    # ... your other URLs ...
]
```

### 6. Run migrations

```bash
python manage.py migrate
```

That's it. Visit `/accounts/login/` to see the login page.

## Configuration

`dj_auth` injects sensible defaults on startup via `AppConfig.ready()`. These are standard allauth and Django settings — no special `DJ_AUTH_*` namespace. Override any of them in your project's `settings.py` using the normal allauth setting names.

| Setting | Default | Description |
|---|---|---|
| `ACCOUNT_LOGIN_METHODS` | `{"email"}` | Login with email only (no username) |
| `ACCOUNT_SIGNUP_FIELDS` | `["email*", "password1*", "password2*"]` | Signup form fields |
| `ACCOUNT_EMAIL_VERIFICATION` | `"optional"` | `"mandatory"`, `"optional"`, or `"none"` |
| `LOGIN_REDIRECT_URL` | `"/"` | Where to go after login |
| `LOGOUT_REDIRECT_URL` | `"/"` | Where to go after logout |
| `MFA_SUPPORTED_TYPES` | `["totp", "recovery_codes", "webauthn"]` | Enabled MFA methods |
| `MFA_PASSKEY_LOGIN_ENABLED` | `True` | Show passkey login button |
| `MFA_PASSKEY_SIGNUP_ENABLED` | `False` | Allow passkey signup (requires mandatory email verification) |
| `MFA_WEBAUTHN_ALLOW_INSECURE_ORIGIN` | `True` | Allow HTTP in development — **set to `False` in production** |
| `SOCIALACCOUNT_PROVIDERS` | `{}` | Social provider credentials (see below) |
| `SITE_ID` | `1` | Django sites framework site ID |

## Template Overriding

`dj_auth` ships templates inside the package (`dj_auth/templates/`). Django's template loader checks project-level `DIRS` first, so you can override any template by placing a file at the same path in your project's template directory.

### Overriding base.html

The main layout is `base.html`. Key blocks:

| Block | Required | Purpose |
|---|---|---|
| `content` | **yes** | Main page content — all auth pages render here |
| `head_title` | no | Page `<title>` text |
| `extra_head` | no | Additional `<head>` content (CSS links, meta tags) |
| `nav` | no | Entire navigation bar |
| `nav_logo_href` | no | Logo link href (default: `/`) |
| `nav_logo_content` | no | Logo icon + site name HTML |
| `nav_links` | no | Right-side nav items |
| `footer` | no | Page footer |
| `extra_body` | no | Scripts before `</body>` |

To customise the layout, create `templates/base.html` in your project (which takes
priority over the package's version via Django's `DIRS` setting). You can start from
scratch or copy `dj_auth/templates/base.html` from the package as a starting point.
Do **not** use `{% extends "base.html" %}` in your override — that's circular.

Example — minimal `base.html` keeping dj_auth's Tailwind styles but adding your own nav:

```html
{# myproject/templates/base.html #}
<!DOCTYPE html>
<html lang="en">
<head>
  <title>{% block head_title %}My App{% endblock %}</title>
  <script src="https://cdn.tailwindcss.com"></script>
  {% block extra_head %}{% endblock %}
</head>
<body>
  <nav><!-- your nav here --></nav>
  <main>{% block content %}{% endblock %}</main>
  {% block extra_body %}{% endblock %}
</body>
</html>
```

### Overriding allauth's internal pages

allauth's built-in pages (TOTP setup, WebAuthn management, etc.) extend
`allauth/layouts/base.html`. To make them match your project's branding:

```html
{# myproject/templates/allauth/layouts/base.html #}
{% extends "base.html" %}
```

## Tailwind CSS

Templates use the Tailwind CSS CDN for zero-configuration development. For production:

1. Install Tailwind: `npm install -D tailwindcss`
2. Configure content paths in `tailwind.config.js`:
   ```js
   content: [
     "./templates/**/*.html",
     // Include dj_auth's package templates:
     "<path-to-venv>/lib/python3.x/site-packages/dj_auth/templates/**/*.html",
   ]
   ```
3. Compile: `npx tailwindcss -o static/css/main.css --minify`
4. Override `extra_head` in your `base.html`:
   ```html
   {% block extra_head %}
   <link rel="stylesheet" href="{% static 'css/main.css' %}">
   {% endblock %}
   ```

## Social Providers

Login/signup buttons are rendered only for providers that are actually usable:
a provider whose `APP` has an empty `client_id` (e.g. credentials left blank in
your `.env`) is hidden automatically, so you can keep provider apps in
`INSTALLED_APPS` and placeholder config in settings without showing dead
buttons. The buttons live in `account/snippets/social_buttons.html`, which you
can override like any other template.

### Google

```python
SOCIALACCOUNT_PROVIDERS = {
    "google": {
        "APP": {
            "client_id": "your-client-id",
            "secret": "your-client-secret",
            "key": "",
        },
        "SCOPE": ["profile", "email"],
        "AUTH_PARAMS": {"access_type": "online"},
    },
}
```

Add `"allauth.socialaccount.providers.google"` to `INSTALLED_APPS`.

### GitHub

```python
SOCIALACCOUNT_PROVIDERS = {
    "github": {
        "APP": {
            "client_id": "your-client-id",
            "secret": "your-client-secret",
            "key": "",
        },
        "SCOPE": ["user:email"],
    },
}
```

Add `"allauth.socialaccount.providers.github"` to `INSTALLED_APPS`.

For other providers, see the [django-allauth documentation](https://docs.allauth.org/en/latest/socialaccount/providers/).

## MFA / Passkeys

MFA is enabled by default when `allauth.mfa` is in `INSTALLED_APPS`. Users manage their security settings at `/accounts/2fa/`.

### Passkey login

Passkeys are enabled by default (`MFA_PASSKEY_LOGIN_ENABLED = True`). The login page shows a "Sign in with a passkey" button automatically.

### Passkey signup

Disabled by default because it requires mandatory email verification:

```python
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
MFA_PASSKEY_SIGNUP_ENABLED = True
```

### Production WebAuthn

For production (HTTPS), remove the insecure origin allowance:

```python
MFA_WEBAUTHN_ALLOW_INSECURE_ORIGIN = False
```

## Running the Example App

```bash
cd examples/basic
pip install -e ../../        # install dj-auth from source
pip install -r requirements.txt
cp .env.example .env         # edit as needed
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
```

Visit http://localhost:8000 to see the example app.

## Running the Test Suite

```bash
pip install -e ".[dev]"
pytest
```

Or with tox (tests against multiple Django versions):

```bash
tox
```

To run just the lint checks:

```bash
tox -e lint
# or
ruff check dj_auth tests
```
