django-auth-headless 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. django_auth_headless-0.1.0/.github/workflows/ci.yml +16 -0
  2. django_auth_headless-0.1.0/.github/workflows/publish.yml +28 -0
  3. django_auth_headless-0.1.0/.gitignore +13 -0
  4. django_auth_headless-0.1.0/LICENSE +21 -0
  5. django_auth_headless-0.1.0/PKG-INFO +191 -0
  6. django_auth_headless-0.1.0/README.md +177 -0
  7. django_auth_headless-0.1.0/manage.py +10 -0
  8. django_auth_headless-0.1.0/pyproject.toml +28 -0
  9. django_auth_headless-0.1.0/src/django_auth_headless/__init__.py +1 -0
  10. django_auth_headless-0.1.0/src/django_auth_headless/adapters.py +18 -0
  11. django_auth_headless-0.1.0/src/django_auth_headless/apps.py +9 -0
  12. django_auth_headless-0.1.0/src/django_auth_headless/conf.py +180 -0
  13. django_auth_headless-0.1.0/src/django_auth_headless/management/__init__.py +0 -0
  14. django_auth_headless-0.1.0/src/django_auth_headless/management/commands/__init__.py +0 -0
  15. django_auth_headless-0.1.0/src/django_auth_headless/management/commands/setup_oauth.py +96 -0
  16. django_auth_headless-0.1.0/src/django_auth_headless/management/commands/verify_oauth.py +122 -0
  17. django_auth_headless-0.1.0/src/django_auth_headless/site_helpers.py +26 -0
  18. django_auth_headless-0.1.0/src/django_auth_headless/urls.py +11 -0
  19. django_auth_headless-0.1.0/src/django_auth_headless/utils.py +67 -0
  20. django_auth_headless-0.1.0/src/django_auth_headless/views.py +36 -0
  21. django_auth_headless-0.1.0/tests/__init__.py +0 -0
  22. django_auth_headless-0.1.0/tests/settings.py +42 -0
  23. django_auth_headless-0.1.0/tests/test_authentication.py +77 -0
  24. django_auth_headless-0.1.0/tests/urls.py +1 -0
  25. django_auth_headless-0.1.0/uv.lock +482 -0
@@ -0,0 +1,16 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: astral-sh/setup-uv@v5
13
+ with:
14
+ version: latest
15
+ - run: uv run python manage.py test
16
+ - run: uv build
@@ -0,0 +1,28 @@
1
+ name: Publish package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: pypi
16
+ url: https://pypi.org/p/django-auth-headless
17
+ steps:
18
+ - name: Check out source
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Set up uv
22
+ uses: astral-sh/setup-uv@v7
23
+
24
+ - name: Build distributions
25
+ run: uv build
26
+
27
+ - name: Publish to PyPI
28
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ .venv/
2
+ .env
3
+ .env.*
4
+ !.env.example
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.sqlite3
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ build/
12
+ dist/
13
+ *.egg-info/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abel Mekonen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.5
2
+ Name: django-auth-headless
3
+ Version: 0.1.0
4
+ Summary: Reusable Django authentication with django-allauth Headless and OAuth providers.
5
+ Author-email: Abel Mekonen <abelmekonen247@gmail.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.13
9
+ Requires-Dist: django-allauth[headless,socialaccount]>=65.20.1
10
+ Requires-Dist: django-cors-headers>=4.9.0
11
+ Requires-Dist: django<7.0,>=6.1.2
12
+ Requires-Dist: python-dotenv>=1.2.4
13
+ Description-Content-Type: text/markdown
14
+
15
+ # django-auth-headless
16
+
17
+ Reusable Django authentication built on django-allauth Headless.
18
+
19
+ The first release focuses on Google OAuth, session authentication, CSRF/CORS
20
+ configuration, and setup and verification commands. The package is designed
21
+ for Django projects using any browser frontend. It does not include a frontend
22
+ or example application.
23
+
24
+ The original learning project, including its React frontend, is available at
25
+ https://github.com/bella-247/DjangoOAuth.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install django-auth-headless
31
+ # or
32
+ uv add django-auth-headless
33
+ ```
34
+
35
+ The package requires Django 6.1, django-allauth with the `headless` and
36
+ `socialaccount` extras, django-cors-headers, and python-dotenv.
37
+
38
+ ## Configure Django
39
+
40
+ In `settings.py`, import the package settings from `django_auth_headless.conf` and
41
+ assign them to the corresponding Django settings:
42
+
43
+ ```python
44
+ from django_auth_headless.conf import *
45
+ ```
46
+
47
+ Keep project-specific `SECRET_KEY`, `DEBUG`, `DATABASES`, `TEMPLATES`,
48
+ `ROOT_URLCONF`, `WSGI_APPLICATION`, `STATIC_URL`, `ALLOWED_HOSTS`, and email
49
+ settings in your project.
50
+
51
+ The exported `INSTALLED_APPS` already includes `django_auth_headless`, so Django
52
+ discovers the package and its management commands. Do not add it a second
53
+ time.
54
+
55
+ Add the package URLs to your project URL configuration:
56
+
57
+ ```python
58
+ from django_auth_headless.urls import urlpatterns as auth_urlpatterns
59
+
60
+ urlpatterns = [
61
+ *auth_urlpatterns,
62
+ ]
63
+ ```
64
+
65
+ Run migrations after installing and configuring the package:
66
+
67
+ ```bash
68
+ python manage.py migrate
69
+ ```
70
+
71
+ ## Environment
72
+
73
+ Create a `.env` file beside `manage.py`:
74
+
75
+ ```dotenv
76
+ DJANGO_FRONTEND_URL=http://localhost:5173
77
+ DJANGO_CORS_ALLOWED_ORIGINS=http://localhost:5173
78
+ DJANGO_CSRF_TRUSTED_ORIGINS=http://localhost:5173
79
+ DJANGO_AUTH_PROVIDERS=google
80
+ DJANGO_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
81
+ DJANGO_GOOGLE_CLIENT_SECRET=your-client-secret
82
+ ```
83
+
84
+ Security settings are also environment-driven:
85
+
86
+ ```dotenv
87
+ DJANGO_SECURE_SSL_REDIRECT=False
88
+ DJANGO_SECURE_HSTS_SECONDS=0
89
+ DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=False
90
+ DJANGO_SECURE_HSTS_PRELOAD=False
91
+ DJANGO_SESSION_COOKIE_SECURE=False
92
+ DJANGO_CSRF_COOKIE_SECURE=False
93
+ DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
94
+ ```
95
+
96
+ Use secure cookies, HTTPS redirect, HSTS, and a production email backend in
97
+ production.
98
+
99
+ ## Management commands
100
+
101
+ The commands are available after `django_auth_headless` is included through the
102
+ exported `INSTALLED_APPS` list and migrations have been applied.
103
+
104
+ ### Configure a provider
105
+
106
+ `setup_oauth` creates or updates the database-backed `SocialApp`, associates it
107
+ with the configured Site, and can write credentials to an env file.
108
+
109
+ ```bash
110
+ # Interactive
111
+ python manage.py setup_oauth
112
+
113
+ # Non-interactive
114
+ python manage.py setup_oauth \
115
+ --provider google \
116
+ --client-id "$DJANGO_GOOGLE_CLIENT_ID" \
117
+ --client-secret "$DJANGO_GOOGLE_CLIENT_SECRET" \
118
+ --domain localhost:8000
119
+
120
+ # Also update an env file
121
+ python manage.py setup_oauth --env-file .env
122
+ ```
123
+
124
+ Options: `--provider`, `--client-id`, `--client-secret`, `--domain`, `--name`,
125
+ and `--env-file`.
126
+
127
+ ### Verify configuration
128
+
129
+ ```bash
130
+ python manage.py verify_oauth
131
+ ```
132
+
133
+ This checks the Site, database `SocialApp` records, provider environment
134
+ variables, and the allauth Headless configuration endpoint.
135
+
136
+ Provider credentials have one source of truth: the database `SocialApp`.
137
+ Environment variables supply credentials to `setup_oauth`; they are not also
138
+ registered as settings-backed provider applications.
139
+
140
+ ## Endpoints
141
+
142
+ The package includes:
143
+
144
+ - `/_allauth/browser/v1/` — django-allauth Headless endpoints.
145
+ - `/accounts/` — provider callback routes.
146
+ - `/api/me` — authenticated current-user response.
147
+
148
+ `GET /api/me` returns:
149
+
150
+ ```json
151
+ {
152
+ "status": 200,
153
+ "data": {
154
+ "user": {
155
+ "id": 1,
156
+ "username": "example",
157
+ "email": "example@example.com"
158
+ }
159
+ }
160
+ }
161
+ ```
162
+
163
+ Unauthenticated requests return HTTP 401.
164
+
165
+ ## Development
166
+
167
+ ```bash
168
+ uv sync --group dev
169
+ uv run python manage.py test
170
+ uv build
171
+ ```
172
+
173
+ ## Publishing
174
+
175
+ Releases are published to PyPI by the `Publish package` GitHub Actions
176
+ workflow when a GitHub Release is published. Configure PyPI Trusted Publishing
177
+ for the `bella-247/django-auth-headless` repository with:
178
+
179
+ - Workflow: `.github/workflows/publish.yml`
180
+ - Environment: `pypi`
181
+ - PyPI project: `django-auth-headless`
182
+
183
+ Update the version in `pyproject.toml`, push a matching tag, and publish a
184
+ GitHub Release for that tag. PyPI versions are immutable, so each release must
185
+ use a new version number.
186
+
187
+ ## Scope
188
+
189
+ This is a Django-only package extracted from a Google OAuth learning project.
190
+ Provider configuration is extensible, but Google OAuth is the documented and
191
+ tested browser flow. The learning project is kept separate as an example.
@@ -0,0 +1,177 @@
1
+ # django-auth-headless
2
+
3
+ Reusable Django authentication built on django-allauth Headless.
4
+
5
+ The first release focuses on Google OAuth, session authentication, CSRF/CORS
6
+ configuration, and setup and verification commands. The package is designed
7
+ for Django projects using any browser frontend. It does not include a frontend
8
+ or example application.
9
+
10
+ The original learning project, including its React frontend, is available at
11
+ https://github.com/bella-247/DjangoOAuth.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install django-auth-headless
17
+ # or
18
+ uv add django-auth-headless
19
+ ```
20
+
21
+ The package requires Django 6.1, django-allauth with the `headless` and
22
+ `socialaccount` extras, django-cors-headers, and python-dotenv.
23
+
24
+ ## Configure Django
25
+
26
+ In `settings.py`, import the package settings from `django_auth_headless.conf` and
27
+ assign them to the corresponding Django settings:
28
+
29
+ ```python
30
+ from django_auth_headless.conf import *
31
+ ```
32
+
33
+ Keep project-specific `SECRET_KEY`, `DEBUG`, `DATABASES`, `TEMPLATES`,
34
+ `ROOT_URLCONF`, `WSGI_APPLICATION`, `STATIC_URL`, `ALLOWED_HOSTS`, and email
35
+ settings in your project.
36
+
37
+ The exported `INSTALLED_APPS` already includes `django_auth_headless`, so Django
38
+ discovers the package and its management commands. Do not add it a second
39
+ time.
40
+
41
+ Add the package URLs to your project URL configuration:
42
+
43
+ ```python
44
+ from django_auth_headless.urls import urlpatterns as auth_urlpatterns
45
+
46
+ urlpatterns = [
47
+ *auth_urlpatterns,
48
+ ]
49
+ ```
50
+
51
+ Run migrations after installing and configuring the package:
52
+
53
+ ```bash
54
+ python manage.py migrate
55
+ ```
56
+
57
+ ## Environment
58
+
59
+ Create a `.env` file beside `manage.py`:
60
+
61
+ ```dotenv
62
+ DJANGO_FRONTEND_URL=http://localhost:5173
63
+ DJANGO_CORS_ALLOWED_ORIGINS=http://localhost:5173
64
+ DJANGO_CSRF_TRUSTED_ORIGINS=http://localhost:5173
65
+ DJANGO_AUTH_PROVIDERS=google
66
+ DJANGO_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
67
+ DJANGO_GOOGLE_CLIENT_SECRET=your-client-secret
68
+ ```
69
+
70
+ Security settings are also environment-driven:
71
+
72
+ ```dotenv
73
+ DJANGO_SECURE_SSL_REDIRECT=False
74
+ DJANGO_SECURE_HSTS_SECONDS=0
75
+ DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=False
76
+ DJANGO_SECURE_HSTS_PRELOAD=False
77
+ DJANGO_SESSION_COOKIE_SECURE=False
78
+ DJANGO_CSRF_COOKIE_SECURE=False
79
+ DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
80
+ ```
81
+
82
+ Use secure cookies, HTTPS redirect, HSTS, and a production email backend in
83
+ production.
84
+
85
+ ## Management commands
86
+
87
+ The commands are available after `django_auth_headless` is included through the
88
+ exported `INSTALLED_APPS` list and migrations have been applied.
89
+
90
+ ### Configure a provider
91
+
92
+ `setup_oauth` creates or updates the database-backed `SocialApp`, associates it
93
+ with the configured Site, and can write credentials to an env file.
94
+
95
+ ```bash
96
+ # Interactive
97
+ python manage.py setup_oauth
98
+
99
+ # Non-interactive
100
+ python manage.py setup_oauth \
101
+ --provider google \
102
+ --client-id "$DJANGO_GOOGLE_CLIENT_ID" \
103
+ --client-secret "$DJANGO_GOOGLE_CLIENT_SECRET" \
104
+ --domain localhost:8000
105
+
106
+ # Also update an env file
107
+ python manage.py setup_oauth --env-file .env
108
+ ```
109
+
110
+ Options: `--provider`, `--client-id`, `--client-secret`, `--domain`, `--name`,
111
+ and `--env-file`.
112
+
113
+ ### Verify configuration
114
+
115
+ ```bash
116
+ python manage.py verify_oauth
117
+ ```
118
+
119
+ This checks the Site, database `SocialApp` records, provider environment
120
+ variables, and the allauth Headless configuration endpoint.
121
+
122
+ Provider credentials have one source of truth: the database `SocialApp`.
123
+ Environment variables supply credentials to `setup_oauth`; they are not also
124
+ registered as settings-backed provider applications.
125
+
126
+ ## Endpoints
127
+
128
+ The package includes:
129
+
130
+ - `/_allauth/browser/v1/` — django-allauth Headless endpoints.
131
+ - `/accounts/` — provider callback routes.
132
+ - `/api/me` — authenticated current-user response.
133
+
134
+ `GET /api/me` returns:
135
+
136
+ ```json
137
+ {
138
+ "status": 200,
139
+ "data": {
140
+ "user": {
141
+ "id": 1,
142
+ "username": "example",
143
+ "email": "example@example.com"
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ Unauthenticated requests return HTTP 401.
150
+
151
+ ## Development
152
+
153
+ ```bash
154
+ uv sync --group dev
155
+ uv run python manage.py test
156
+ uv build
157
+ ```
158
+
159
+ ## Publishing
160
+
161
+ Releases are published to PyPI by the `Publish package` GitHub Actions
162
+ workflow when a GitHub Release is published. Configure PyPI Trusted Publishing
163
+ for the `bella-247/django-auth-headless` repository with:
164
+
165
+ - Workflow: `.github/workflows/publish.yml`
166
+ - Environment: `pypi`
167
+ - PyPI project: `django-auth-headless`
168
+
169
+ Update the version in `pyproject.toml`, push a matching tag, and publish a
170
+ GitHub Release for that tag. PyPI versions are immutable, so each release must
171
+ use a new version number.
172
+
173
+ ## Scope
174
+
175
+ This is a Django-only package extracted from a Google OAuth learning project.
176
+ Provider configuration is extensible, but Google OAuth is the documented and
177
+ tested browser flow. The learning project is kept separate as an example.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python
2
+ import os
3
+ import sys
4
+
5
+
6
+ if __name__ == "__main__":
7
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
8
+ from django.core.management import execute_from_command_line
9
+
10
+ execute_from_command_line(sys.argv)
@@ -0,0 +1,28 @@
1
+ [project]
2
+ name = "django-auth-headless"
3
+ version = "0.1.0"
4
+ description = "Reusable Django authentication with django-allauth Headless and OAuth providers."
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ license = { text = "MIT" }
8
+ authors = [
9
+ { name = "Abel Mekonen", email = "abelmekonen247@gmail.com" },
10
+ ]
11
+ dependencies = [
12
+ "django>=6.1.2,<7.0",
13
+ "django-allauth[headless,socialaccount]>=65.20.1",
14
+ "django-cors-headers>=4.9.0",
15
+ "python-dotenv>=1.2.4",
16
+ ]
17
+
18
+ [dependency-groups]
19
+ dev = [
20
+ "build>=1.2.2",
21
+ ]
22
+
23
+ [build-system]
24
+ requires = ["hatchling>=1.27"]
25
+ build-backend = "hatchling.build"
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = ["src/django_auth_headless"]
@@ -0,0 +1 @@
1
+ """Reusable Django authentication configuration."""
@@ -0,0 +1,18 @@
1
+ """Custom django-allauth hooks for keeping local user data in sync."""
2
+
3
+ from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
4
+ from allauth.socialaccount.models import SocialLogin
5
+
6
+
7
+ class AuthenticationSocialAccountAdapter(DefaultSocialAccountAdapter):
8
+ """Fill missing local email addresses from the authenticated provider."""
9
+
10
+ def pre_social_login(self, request, sociallogin: SocialLogin) -> None:
11
+ user = sociallogin.user
12
+ provider_email = user.email or sociallogin.account.extra_data.get("email", "")
13
+
14
+ if not user.email and isinstance(provider_email, str) and provider_email:
15
+ user.email = provider_email
16
+ user.save(update_fields=["email"])
17
+
18
+ super().pre_social_login(request, sociallogin)
@@ -0,0 +1,9 @@
1
+ """Django app configuration for the authentication module."""
2
+
3
+ from django.apps import AppConfig
4
+
5
+
6
+ class AuthenticationConfig(AppConfig):
7
+ default_auto_field = "django.db.models.BigAutoField"
8
+ name = __package__
9
+ verbose_name = "Authentication"