Metadata-Version: 2.3
Name: django-clerk-sdk
Version: 1.0.0
Summary: Django and DRF integration for Clerk authentication with request token verification, Clerk-to-Django user synchronization, cache-backed auth reuse, and Django signals for auth observability.
Keywords: django,djangorestframework,drf,clerk,authentication,jwt
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Session
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Dist: clerk-backend-api>=3.3.1
Requires-Dist: django>=5.2.7
Requires-Dist: django-guardian>=3.2.0
Requires-Dist: djangorestframework>=3.16.0
Requires-Dist: djangorestframework-stubs>=3.16.6
Requires-Dist: pytest>=8.0 ; extra == 'dev'
Requires-Dist: pytest-django>=4.8 ; extra == 'dev'
Requires-Python: >=3.14
Provides-Extra: dev
Description-Content-Type: text/markdown

# Django Clerk SDK

`django-clerk-sdk` is a Django and Django REST Framework integration for Clerk authentication.

It validates Clerk session tokens on incoming requests, syncs Clerk user data into your Django user model, caches successful authentications, and emits Django signals for observability.

## What This Package Provides

- `ClerkMiddleware` for request-level authentication in Django.
- `ClerkAuthentication` for DRF endpoints.
- `ClerkClient` / `clerk_client` for direct programmatic use.
- Automatic user sync from Clerk to Django user records.
- Token-result caching through Django's cache backend.
- Signals for auth success, auth failure, and cache misses.

## Installation

```bash
pip install django-clerk-sdk
```

## Quick Setup

### 1. Add apps

```python
INSTALLED_APPS = [
    # ...
    "django_clerk_sdk",
    "django_clerk_sdk.users",  # Optional if you want the included ClerkUser model
]
```

If you use the packaged user model:

```python
AUTH_USER_MODEL = "users.ClerkUser"
```

### 2. Add middleware

Place Clerk middleware after Django auth middleware so session auth still works when no Clerk credentials are present.

```python
MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django_clerk_sdk.core.auth.clerk.middleware.ClerkMiddleware",
    # ...
]
```

### 3. Configure DRF authentication

```python
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "django_clerk_sdk.core.auth.clerk.authentication.ClerkAuthentication",
        # "rest_framework.authentication.SessionAuthentication",  # optional fallback
    ),
}
```

### 4. Configure Clerk settings

```python
# Required
CLERK_SECRET_KEY = "sk_test_..."

# Optional
CLERK_AUTH_PARTIES = ["http://localhost:3000", "https://your-app.com"]
CLERK_AUDIENCE = ["your-api-audience"]  # passed to Clerk AuthenticateRequestOptions
CLERK_JWT_KEY = "..."                    # optional Clerk JWT verification key
CLERK_API_URL = "https://api.clerk.com" # custom Clerk API base URL
CLERK_TIMEOUT_MS = 5000
CLERK_CLOCK_SKEW_IN_MS = 5000
CLERK_CACHE_TIMEOUT = 300                 # seconds
```

## Authentication Behavior

Token sources checked by this SDK:

- `Authorization: Bearer <token>` header
- Clerk session cookie names starting with `__session`

Flow:

1. Extract token from header/cookie.
2. Check cache (`sha256(token)`-based key).
3. If cache miss, call Clerk `authenticate_request(...)`.
4. If signed in, fetch Clerk user details and sync into Django user.
5. Save user PK in cache and return authenticated Django user.

When Clerk credentials are missing, middleware does not override an existing session-authenticated `request.user`.

## User Synchronization Rules

`ClerkClient.sync_django_user(...)`:

- Finds existing users by `clerk_user_id` first, then by case-insensitive email.
- Creates a new user if none exists.
- Syncs supported fields when present on your model:
  - `clerk_user_id`, `email`, `username`, `first_name`, `last_name`, `image`, `last_active_at`, `is_active`
- Converts `last_active_at` UNIX timestamps (seconds or milliseconds) to timezone-aware UTC datetimes.
- Deduplicates usernames (`name`, `name-2`, `name-3`, ...).
- Sets unusable password on newly created users when available.

If your custom user model omits some fields, only available fields are updated.

## Public API

```python
from django_clerk_sdk.core.auth.clerk import (
    ClerkAuthentication,
    ClerkClient,
    ClerkMiddleware,
    clerk_client,
)
```

Direct client usage:

```python
from django_clerk_sdk.core.auth.clerk.sdk import clerk_client

state = clerk_client.authenticate_request(request)
user_id = clerk_client.get_user_id(state)
clerk_user = clerk_client.get_user_details(user_id)
django_user = clerk_client.sync_django_user(clerk_user)
```

## Signals

```python
from django_clerk_sdk.core.signals import (
    clerk_auth_success,
    clerk_auth_failed,
    clerk_cache_miss,
)
```

Emitted events:

- `clerk_auth_success`: `user`, `source` (`"cache"` or `"api"`)
- `clerk_auth_failed`: `reason`, `token_hash`
- `clerk_cache_miss`: `token_hash`

Example:

```python
from django.dispatch import receiver
from django_clerk_sdk.core.signals import clerk_auth_success, clerk_auth_failed

@receiver(clerk_auth_success)
def on_clerk_auth_success(sender, user, source, **kwargs):
    print(f"Clerk auth success for {user.pk} via {source}")

@receiver(clerk_auth_failed)
def on_clerk_auth_failed(sender, reason, token_hash, **kwargs):
    print(f"Clerk auth failed ({reason}) token={token_hash}")
```

## Notes

- The package exposes a script entry point (`django-clerk-sdk`) only to explain that this is a library package, not a standalone CLI.
- Minimum Python version is currently `3.14` per package metadata.
