Skip to main content

Freehand Kit Auth

CI PyPI Python

Freehand Kit Auth is a configurable Django REST Framework authentication API for applications that own their Django user model and need a secure local-account flow. It provides signup, configurable email verification, login, JWT lifecycle endpoints, password recovery, and a safe current-user API. It also mounts an OpenAPI schema and Swagger UI automatically.

The PyPI distribution is freehand-kit-auth; the Python import and Django app entry are both fk_auth.

When to use it

Use this package when a Django project needs first-party email/username and password authentication, wants to keep its own user model, and exposes a DRF API.

It deliberately does not implement OAuth/social login, OIDC, SAML, passkeys, tenancy, MFA, or a complete RBAC system. Roles, when enabled, only assign a server-selected default Django Group at signup.

Requirements

  • Python 3.11, 3.12, or 3.13
  • Django 5.2 through 6.0
  • Django REST Framework 3.17.x

Install

python -m pip install freehand-kit-auth

# Install this extra when using Redis for OTP verification or Django's Redis cache.
python -m pip install "freehand-kit-auth[redis]"

# Install this extra when signing JWTs with RSA keys.
python -m pip install "freehand-kit-auth[crypto]"

This is the recommended starting point for a new production application. The host application owns the user model; fk_auth never creates, replaces, or migrates that model.

1. Create the host user model before the first migration

# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
    email = models.EmailField(unique=True)

The unique email constraint is the safe production default. Set AUTH_USER_MODEL before running the first migrate in a new project.

2. Configure Django settings

The example below uses link verification. Environment-variable loading is owned by your Django project; fk_auth intentionally does not read .env files itself.

# settings.py
import os

INSTALLED_APPS = [
    # Django's standard applications and your host applications...
    "accounts",
    "rest_framework",
    "rest_framework_simplejwt.token_blacklist",
    "drf_spectacular",
    "fk_auth",
]

AUTH_USER_MODEL = "accounts.User"

REST_FRAMEWORK = {
    # Keep any existing host entries as well.
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "fk_auth.tokens.FreehandJWTAuthentication",
    ],
    "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
}

DEFAULT_FROM_EMAIL = os.environ["DEFAULT_FROM_EMAIL"]

FREEHAND_KIT_AUTH = {
    "USER": {
        "EMAIL_FIELD": "email",
        "REQUIRE_UNIQUE_EMAIL": True,
        "REGISTRATION_FIELDS": ("username", "email"),
        "PROFILE_READ_FIELDS": ("username", "email"),
        "PROFILE_WRITE_FIELDS": ("username",),
    },
    "EMAIL": {
        "FROM_EMAIL": DEFAULT_FROM_EMAIL,
        "VERIFICATION_URL_TEMPLATE": "https://app.example.com/verify-email?token={token}",
        "PASSWORD_RESET_URL_TEMPLATE": "https://app.example.com/reset-password?uid={uid}&token={token}",
    },
    "VERIFICATION": {"METHOD": "link"},
    "LOGIN": {"IDENTIFIERS": ("email", "username")},
    "JWT": {
        "ALGORITHM": "HS256",
        "SIGNING_KEY": os.environ["FK_AUTH_JWT_SIGNING_KEY"],
        "ACCESS_TOKEN_LIFETIME_SECONDS": 300,
        "REFRESH_TOKEN_LIFETIME_SECONDS": 86400,
        "ROTATE_REFRESH_TOKENS": True,
        "BLACKLIST_AFTER_ROTATION": True,
    },
}

For local development only, a console email backend is useful and the shared-cache check may be disabled:

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
FREEHAND_KIT_AUTH["THROTTLE"] = {"REQUIRE_SHARED_CACHE": False}

Do not use that throttle setting in production.

3. Mount the API and Swagger UI

# project/urls.py
from django.urls import include, path

urlpatterns = [
    path("api/", include("fk_auth.urls")),
]

Run the host migrations and validate the integration:

python manage.py makemigrations accounts
python manage.py migrate
python manage.py check --tag fk_auth
python manage.py runserver

Swagger UI is now available at http://localhost:8000/api/docs/ and the OpenAPI document is at http://localhost:8000/api/schema/.

4. Use the API

Create an account:

curl -X POST http://localhost:8000/api/signup/ \
  -H "Content-Type: application/json" \
  -d '{"username":"ada","email":"ada@example.com","password":"A-strong-password-123!","password_confirm":"A-strong-password-123!"}'

The verification email contains a link to your frontend. Read its token query parameter and send it to the API after the frontend opens the link:

curl -X POST http://localhost:8000/api/email/verify/ \
  -H "Content-Type: application/json" \
  -d '{"token":"token-from-the-verification-link"}'

Log in with either enabled identifier. The response contains access and refresh JWTs:

curl -X POST http://localhost:8000/api/login/ \
  -H "Content-Type: application/json" \
  -d '{"identifier":"ada@example.com","password":"A-strong-password-123!"}'

Use the access token on protected routes, including the current-user endpoint:

curl http://localhost:8000/api/me/ \
  -H "Authorization: Bearer <access-token>"

Choose email verification behaviour

Set FREEHAND_KIT_AUTH["VERIFICATION"]["METHOD"] to one of these values:

Method Verification request Use case
link {"token": "..."} Recommended for browser or mobile-app frontend flows.
token {"token": "..."} A simple API-only flow; email contains a high-entropy token.
otp {"email": "...", "otp": "..."} Email OTP flow backed by Redis.
none No verification endpoints are mounted. Only when account verification is intentionally not required.

For OTP, install the Redis extra and provide a dedicated Redis URL and a 32-byte minimum secret pepper. Swagger automatically shows the email and otp request shape when OTP mode is active.

FREEHAND_KIT_AUTH["VERIFICATION"] = {
    "METHOD": "otp",
    "OTP": {
        "LENGTH": 6,                 # 6 through 12
        "ALPHABET": "digits",        # digits or alphanumeric
        "LIFETIME_SECONDS": 600,
        "MAX_ATTEMPTS": 5,
        "RESEND_COOLDOWN_SECONDS": 60,
        "MAX_SENDS_PER_HOUR": 5,
        "REDIS_URL": os.environ["FK_AUTH_OTP_REDIS_URL"],
        "PEPPER": os.environ["FK_AUTH_OTP_PEPPER"],
    },
}

Endpoints

All paths below are relative to the prefix where you mount fk_auth.urls.

Method Path Purpose
POST signup/ Create an account.
POST email/verify/ Confirm a link/token or OTP, according to the selected method.
POST email/resend/ Request another verification message.
POST login/ Receive an access/refresh JWT pair.
POST token/refresh/, token/verify/, logout/ Manage and revoke tokens.
POST password/forgot/, password/reset/, password/change/ Recover or change a password.
GET, PATCH me/ Read or update only host-approved profile fields.
GET schema/, docs/ OpenAPI schema and Swagger UI.

Production checklist

  • Use a custom user model with a unique email field; configure exactly which user fields are accepted at registration and exposed through me/.
  • Use a dedicated JWT signing key, stored in a secret manager. Never reuse Django's SECRET_KEY by default.
  • Configure real SMTP, HTTPS frontend URLs, and DEFAULT_FROM_EMAIL.
  • Use Redis or another shared Django cache for authentication throttles. The default production check rejects local-memory and dummy caches.
  • For OTP, use a protected Redis service and a separate 32-byte-or-longer pepper.
  • Run python manage.py check --tag fk_auth in deployment and CI.
  • Keep rest_framework_simplejwt.token_blacklist installed when using refresh-token rotation and logout.

Documentation

Development

python -m pip install -e ".[dev]"
pytest
ruff check .
python -m build
twine check dist/*

The GitHub Actions workflow runs the supported Python/Django matrix, linting, typing, package validation, dependency auditing, and PostgreSQL/Redis/Mailpit integration tests.

License

MIT. See LICENSE.

Metadata

Release files for freehand-kit-auth 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for freehand-kit-auth 1.0.1
File Size Uploaded
freehand_kit_auth-1.0.1.tar.gz 49.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for freehand-kit-auth 1.0.1
File Interpreter ABI Platform
freehand_kit_auth-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 88.0 kB

Release files / freehand_kit_auth-1.0.1.tar.gz

Download URL freehand_kit_auth-1.0.1.tar.gz
Size 49.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d6e9729e74b6a34ea826ce9ce679beaa2e856c737d586e4c702b5916505c3725
BLAKE2b-256 checksum
How to use checksums
c506c81bb97066cd7822fdadcafe2ae797b9f4c9a0b4f1c745ad282e29b9afc2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / freehand_kit_auth-1.0.1-py3-none-any.whl

Download URL freehand_kit_auth-1.0.1-py3-none-any.whl
Size 38.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c228034886d6b84dbce832fcad2784c5c9a79decd95d41a1007a7b6e41be9016
BLAKE2b-256 checksum
How to use checksums
cc68ac3cfe413157c1c16f2ef1b0f02bf7262c53e2fc6cf2c0835e9206683032
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page