django-clerk-users 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
- django_clerk_users/authentication/backends.py +40 -46
- django_clerk_users/utils.py +34 -7
- {django_clerk_users-0.1.0.dist-info → django_clerk_users-0.1.2.dist-info}/METADATA +1 -1
- {django_clerk_users-0.1.0.dist-info → django_clerk_users-0.1.2.dist-info}/RECORD +6 -6
- {django_clerk_users-0.1.0.dist-info → django_clerk_users-0.1.2.dist-info}/WHEEL +0 -0
- {django_clerk_users-0.1.0.dist-info → django_clerk_users-0.1.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,7 +8,7 @@ import logging
|
|
|
8
8
|
from typing import TYPE_CHECKING, Any
|
|
9
9
|
|
|
10
10
|
from django.contrib.auth import get_user_model
|
|
11
|
-
from django.contrib.auth.backends import
|
|
11
|
+
from django.contrib.auth.backends import ModelBackend
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from django.http import HttpRequest
|
|
@@ -18,72 +18,66 @@ if TYPE_CHECKING:
|
|
|
18
18
|
logger = logging.getLogger(__name__)
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class ClerkBackend(
|
|
21
|
+
class ClerkBackend(ModelBackend):
|
|
22
22
|
"""
|
|
23
23
|
Django authentication backend for Clerk.
|
|
24
24
|
|
|
25
|
-
This backend
|
|
26
|
-
username/password.
|
|
27
|
-
|
|
25
|
+
This backend extends Django's ModelBackend to add Clerk ID authentication
|
|
26
|
+
while preserving standard username/password authentication. This allows:
|
|
27
|
+
|
|
28
|
+
- Superusers to log into Django admin with email/password
|
|
29
|
+
- Clerk users to authenticate via JWT tokens (clerk_id)
|
|
30
|
+
- All standard Django permission checks to work as expected
|
|
28
31
|
|
|
29
32
|
To use this backend, add it to AUTHENTICATION_BACKENDS in settings:
|
|
30
33
|
|
|
31
34
|
AUTHENTICATION_BACKENDS = [
|
|
32
35
|
'django_clerk_users.authentication.ClerkBackend',
|
|
33
36
|
]
|
|
37
|
+
|
|
38
|
+
This is the only backend you need - it handles both Clerk authentication
|
|
39
|
+
and standard Django authentication (for admin access, etc.).
|
|
34
40
|
"""
|
|
35
41
|
|
|
36
42
|
def authenticate(
|
|
37
43
|
self,
|
|
38
44
|
request: "HttpRequest | None" = None,
|
|
39
|
-
|
|
45
|
+
username: str | None = None,
|
|
46
|
+
password: str | None = None,
|
|
40
47
|
**kwargs: Any,
|
|
41
48
|
) -> "AbstractClerkUser | None":
|
|
42
49
|
"""
|
|
43
|
-
Authenticate a user by
|
|
50
|
+
Authenticate a user by Clerk ID or username/password.
|
|
51
|
+
|
|
52
|
+
If a clerk_id is provided in kwargs, authenticates via Clerk ID lookup.
|
|
53
|
+
Otherwise, falls back to Django's standard username/password
|
|
54
|
+
authentication (inherited from ModelBackend).
|
|
44
55
|
|
|
45
56
|
Args:
|
|
46
57
|
request: The current HTTP request (optional).
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
username: The username (email) for standard auth (optional).
|
|
59
|
+
password: The password for standard auth (optional).
|
|
60
|
+
**kwargs: Additional keyword arguments. If 'clerk_id' is present,
|
|
61
|
+
Clerk authentication is used instead of password auth.
|
|
49
62
|
|
|
50
63
|
Returns:
|
|
51
64
|
The authenticated user or None if authentication fails.
|
|
52
65
|
"""
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
This method is called by Django's authentication middleware
|
|
73
|
-
to restore the user from the session.
|
|
74
|
-
|
|
75
|
-
Args:
|
|
76
|
-
user_id: The user's primary key.
|
|
77
|
-
|
|
78
|
-
Returns:
|
|
79
|
-
The user instance or None if not found.
|
|
80
|
-
"""
|
|
81
|
-
User = get_user_model()
|
|
82
|
-
|
|
83
|
-
try:
|
|
84
|
-
user = User.objects.get(pk=user_id)
|
|
85
|
-
if user.is_active:
|
|
86
|
-
return user
|
|
87
|
-
return None
|
|
88
|
-
except User.DoesNotExist:
|
|
89
|
-
return None
|
|
66
|
+
# If clerk_id is provided, authenticate via Clerk
|
|
67
|
+
clerk_id = kwargs.pop("clerk_id", None)
|
|
68
|
+
if clerk_id:
|
|
69
|
+
User = get_user_model()
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
user = User.objects.get(clerk_id=clerk_id)
|
|
73
|
+
if user.is_active:
|
|
74
|
+
return user
|
|
75
|
+
logger.debug(f"User {clerk_id} is inactive")
|
|
76
|
+
return None
|
|
77
|
+
except User.DoesNotExist:
|
|
78
|
+
logger.debug(f"No user found with clerk_id: {clerk_id}")
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
# Otherwise, fall back to standard Django authentication
|
|
82
|
+
# This enables superuser login via Django admin
|
|
83
|
+
return super().authenticate(request, username, password, **kwargs)
|
django_clerk_users/utils.py
CHANGED
|
@@ -28,7 +28,9 @@ def update_or_create_clerk_user(
|
|
|
28
28
|
Update or create a Django user from Clerk data.
|
|
29
29
|
|
|
30
30
|
Fetches user data from the Clerk API and creates or updates
|
|
31
|
-
the corresponding Django user.
|
|
31
|
+
the corresponding Django user. If a user with the same email
|
|
32
|
+
already exists (e.g., a superuser created via createsuperuser),
|
|
33
|
+
it will be linked to the Clerk ID rather than creating a duplicate.
|
|
32
34
|
|
|
33
35
|
Args:
|
|
34
36
|
clerk_user_id: The Clerk user ID.
|
|
@@ -70,17 +72,42 @@ def update_or_create_clerk_user(
|
|
|
70
72
|
|
|
71
73
|
# Prepare user data
|
|
72
74
|
user_data = {
|
|
73
|
-
"email": primary_email,
|
|
74
75
|
"first_name": getattr(clerk_user, "first_name", "") or "",
|
|
75
76
|
"last_name": getattr(clerk_user, "last_name", "") or "",
|
|
76
77
|
"image_url": getattr(clerk_user, "image_url", "") or "",
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
#
|
|
80
|
-
user
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
# First, try to find by clerk_id
|
|
81
|
+
user = User.objects.filter(clerk_id=clerk_user_id).first()
|
|
82
|
+
created = False
|
|
83
|
+
|
|
84
|
+
if user:
|
|
85
|
+
# Update existing Clerk-linked user
|
|
86
|
+
for key, value in user_data.items():
|
|
87
|
+
setattr(user, key, value)
|
|
88
|
+
user.email = primary_email
|
|
89
|
+
user.save()
|
|
90
|
+
else:
|
|
91
|
+
# No user with this clerk_id - check if email already exists
|
|
92
|
+
user = User.objects.filter(email__iexact=primary_email).first()
|
|
93
|
+
|
|
94
|
+
if user:
|
|
95
|
+
# Link existing Django user to Clerk
|
|
96
|
+
user.clerk_id = clerk_user_id
|
|
97
|
+
for key, value in user_data.items():
|
|
98
|
+
setattr(user, key, value)
|
|
99
|
+
user.save()
|
|
100
|
+
logger.info(
|
|
101
|
+
f"Linked existing user {user.email} to Clerk ID {clerk_user_id}"
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
# Create new user
|
|
105
|
+
user = User.objects.create(
|
|
106
|
+
clerk_id=clerk_user_id,
|
|
107
|
+
email=primary_email,
|
|
108
|
+
**user_data,
|
|
109
|
+
)
|
|
110
|
+
created = True
|
|
84
111
|
|
|
85
112
|
# Update cache
|
|
86
113
|
set_cached_user(clerk_user_id, user)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-clerk-users
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Integrate Clerk with Django
|
|
5
5
|
Project-URL: Changelog, https://github.com/jmitchel3/django-clerk-users
|
|
6
6
|
Project-URL: Documentation, https://github.com/jmitchel3/django-clerk-users
|
|
@@ -9,9 +9,9 @@ django_clerk_users/managers.py,sha256=HvSkGeiQhjA6EFXrW4GTlxXtlRDtlT54BbwbvnNuOW
|
|
|
9
9
|
django_clerk_users/models.py,sha256=DMcEnGNioGX5xsP4U47ich1L_UoZNAFEDb-vZVVV8Tk,5210
|
|
10
10
|
django_clerk_users/settings.py,sha256=pRyt_kSPWOT8CkTvyce3sf0RxfIoG5DEwnGUT8bIDi8,1305
|
|
11
11
|
django_clerk_users/testing.py,sha256=ZoYi7dG_HjSp19_c1AvILOoCfHlofs7LN-5ALS_UhDw,12160
|
|
12
|
-
django_clerk_users/utils.py,sha256=
|
|
12
|
+
django_clerk_users/utils.py,sha256=OMB2OCv-SUk6iAbWU6NPo-Psq63dcVJRSDTkAICFNmY,7002
|
|
13
13
|
django_clerk_users/authentication/__init__.py,sha256=PStQVzC-CA2Guyo4ksrxP58o93mfygW4qcJXWEjs6ak,614
|
|
14
|
-
django_clerk_users/authentication/backends.py,sha256=
|
|
14
|
+
django_clerk_users/authentication/backends.py,sha256=bDJ2mEO66xhcJPc6f-jYa3F9x-PJ4RJrm9GD-pCTo6Y,2855
|
|
15
15
|
django_clerk_users/authentication/drf.py,sha256=AqHvZTe9RnxN7FVzlSUXR72QBj2imGglkx9rpOrRDIk,3215
|
|
16
16
|
django_clerk_users/authentication/utils.py,sha256=tpnRXQLbQPkosKV8OhxtXpapuema4c08g58YYmMl3js,5326
|
|
17
17
|
django_clerk_users/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -37,7 +37,7 @@ django_clerk_users/webhooks/handlers.py,sha256=GnotJNhN809DsrbfZjtJD0KurThKyAXZS
|
|
|
37
37
|
django_clerk_users/webhooks/security.py,sha256=Ig2ZxF8SxX5o-4bNRehFhip4hVvcQxoGsTj3sTY3WSU,3461
|
|
38
38
|
django_clerk_users/webhooks/signals.py,sha256=bytshg7IMDnlvnCZ0_TGjUXZZLRNxtn2RSx97qacZ-w,1668
|
|
39
39
|
django_clerk_users/webhooks/views.py,sha256=0-ilzzO7tBfc-pENMy0ZSSkQ4uPqH2QAt249EK2wQKA,2287
|
|
40
|
-
django_clerk_users-0.1.
|
|
41
|
-
django_clerk_users-0.1.
|
|
42
|
-
django_clerk_users-0.1.
|
|
43
|
-
django_clerk_users-0.1.
|
|
40
|
+
django_clerk_users-0.1.2.dist-info/METADATA,sha256=FXGQeLLxETfuOZb53Zn-m4tbXonJDjldPgjx0z6TsRY,8687
|
|
41
|
+
django_clerk_users-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
42
|
+
django_clerk_users-0.1.2.dist-info/licenses/LICENSE,sha256=X4PZDRQG4RmPhHU5c0G21Ki9LXWDCuLQ8W4mnED5RDU,1071
|
|
43
|
+
django_clerk_users-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|