plain.auth 0.15.0__py3-none-any.whl → 0.17.0__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.
plain/auth/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # plain-auth changelog
2
2
 
3
+ ## [0.17.0](https://github.com/dropseed/plain/releases/plain-auth@0.17.0) (2025-09-12)
4
+
5
+ ### What's changed
6
+
7
+ - Model managers are now accessed via `.query` instead of `.objects` ([037a239](https://github.com/dropseed/plain/commit/037a239ef4))
8
+ - Updated to require Python 3.13 minimum ([d86e307](https://github.com/dropseed/plain/commit/d86e307efb))
9
+
10
+ ### Upgrade instructions
11
+
12
+ - Replace any usage of `Model.objects` with `Model.query` in your code (e.g., `User.objects.get()` becomes `User.query.get()`)
13
+
14
+ ## [0.16.0](https://github.com/dropseed/plain/releases/plain-auth@0.16.0) (2025-08-19)
15
+
16
+ ### What's changed
17
+
18
+ - Removed automatic CSRF token rotation on login as part of CSRF system refactor using Sec-Fetch-Site headers ([9551508](https://github.com/dropseed/plain/commit/955150800c))
19
+ - Updated README with improved documentation, examples, and better package description ([4ebecd1](https://github.com/dropseed/plain/commit/4ebecd1856))
20
+
21
+ ### Upgrade instructions
22
+
23
+ - No changes required
24
+
3
25
  ## [0.15.0](https://github.com/dropseed/plain/releases/plain-auth@0.15.0) (2025-07-22)
4
26
 
5
27
  ### What's changed
plain/auth/README.md CHANGED
@@ -1,23 +1,53 @@
1
1
  # plain.auth
2
2
 
3
- Add users to your app and define which views they can access.
3
+ **Add users to your app and decide what they can access.**
4
4
 
5
- To log a user in, you'll want to pair this package with:
5
+ - [Overview](#overview)
6
+ - [Authentication setup](#authentication-setup)
7
+ - [Settings configuration](#settings-configuration)
8
+ - [Creating a user model](#creating-a-user-model)
9
+ - [Login views](#login-views)
10
+ - [Checking if a user is logged in](#checking-if-a-user-is-logged-in)
11
+ - [Restricting views](#restricting-views)
12
+ - [Installation](#installation)
6
13
 
7
- - `plain-passwords`
8
- - `plain-oauth`
9
- - `plain-passkeys` (TBD)
10
- - `plain-passlinks` (TBD)
14
+ ## Overview
11
15
 
12
- ## Installation
16
+ The `plain.auth` package provides user authentication and authorization for Plain applications. Here's a basic example of checking if a user is logged in:
17
+
18
+ ```python
19
+ # In a view
20
+ if request.user:
21
+ print(f"Hello, {request.user.email}!")
22
+ else:
23
+ print("You are not logged in.")
24
+ ```
25
+
26
+ And restricting a view to logged-in users:
27
+
28
+ ```python
29
+ from plain.auth.views import AuthViewMixin
30
+ from plain.views import View
31
+
32
+ class ProfileView(AuthViewMixin, View):
33
+ login_required = True
34
+
35
+ def get(self):
36
+ return f"Welcome, {self.request.user.email}!"
37
+ ```
38
+
39
+ ## Authentication setup
40
+
41
+ ### Settings configuration
42
+
43
+ Configure your authentication settings in `app/settings.py`:
13
44
 
14
45
  ```python
15
- # app/settings.py
16
46
  INSTALLED_PACKAGES = [
17
47
  # ...
18
48
  "plain.auth",
19
49
  "plain.sessions",
20
- "plain.passwords",
50
+ "plain.passwords", # Or another auth method
21
51
  ]
22
52
 
23
53
  MIDDLEWARE = [
@@ -29,7 +59,9 @@ AUTH_USER_MODEL = "users.User"
29
59
  AUTH_LOGIN_URL = "login"
30
60
  ```
31
61
 
32
- Create your own user model (`plain create users`).
62
+ ### Creating a user model
63
+
64
+ Create your own user model using `plain create users` or manually:
33
65
 
34
66
  ```python
35
67
  # app/users/models.py
@@ -47,12 +79,21 @@ class User(models.Model):
47
79
  return self.email
48
80
  ```
49
81
 
50
- Define your URL/view where users can log in.
82
+ ### Login views
83
+
84
+ To log users in, you'll need to pair this package with an authentication method:
85
+
86
+ - `plain-passwords` - Username/password authentication
87
+ - `plain-oauth` - OAuth provider authentication
88
+ - `plain-passkeys` (TBD) - WebAuthn/passkey authentication
89
+ - `plain-passlinks` (TBD) - Magic link authentication
90
+
91
+ Example with password authentication:
51
92
 
52
93
  ```python
53
94
  # app/urls.py
54
- from plain.auth.views import LoginView, LogoutView
55
- from plain.urls import include, path
95
+ from plain.auth.views import LogoutView
96
+ from plain.urls import path
56
97
  from plain.passwords.views import PasswordLoginView
57
98
 
58
99
 
@@ -68,9 +109,9 @@ urlpatterns = [
68
109
 
69
110
  ## Checking if a user is logged in
70
111
 
71
- A `request.user` will either be `None` or point to an instance of a your `AUTH_USER_MODEL`.
112
+ A `request.user` will either be `None` or point to an instance of your `AUTH_USER_MODEL`.
72
113
 
73
- So in templates you can do:
114
+ In templates:
74
115
 
75
116
  ```html
76
117
  {% if request.user %}
@@ -80,7 +121,7 @@ So in templates you can do:
80
121
  {% endif %}
81
122
  ```
82
123
 
83
- Or in Python:
124
+ In Python code:
84
125
 
85
126
  ```python
86
127
  if request.user:
@@ -91,7 +132,7 @@ else:
91
132
 
92
133
  ## Restricting views
93
134
 
94
- Use the `AuthViewMixin` to restrict views to logged in users, admin users, or custom logic.
135
+ Use the [`AuthViewMixin`](./views.py#AuthViewMixin) to restrict views to logged-in users, admin users, or custom logic:
95
136
 
96
137
  ```python
97
138
  from plain.auth.views import AuthViewMixin
@@ -114,3 +155,17 @@ class CustomPermissionView(AuthViewMixin, View):
114
155
  if not self.request.user.is_special:
115
156
  raise PermissionDenied("You're not special!")
116
157
  ```
158
+
159
+ The [`AuthViewMixin`](./views.py#AuthViewMixin) provides:
160
+
161
+ - `login_required` - Requires a logged-in user
162
+ - `admin_required` - Requires `user.is_admin` to be True
163
+ - `check_auth()` - Override for custom authorization logic
164
+
165
+ ## Installation
166
+
167
+ Install the `plain.auth` package from [PyPI](https://pypi.org/project/plain.auth/):
168
+
169
+ ```bash
170
+ uv add plain.auth
171
+ ```
plain/auth/sessions.py CHANGED
@@ -1,4 +1,3 @@
1
- from plain.csrf.middleware import rotate_token
2
1
  from plain.exceptions import ImproperlyConfigured
3
2
  from plain.models import models_registry
4
3
  from plain.runtime import settings
@@ -76,7 +75,6 @@ def login(request, user):
76
75
  request.session[USER_HASH_SESSION_KEY] = session_auth_hash
77
76
  if hasattr(request, "user"):
78
77
  request.user = user
79
- rotate_token(request)
80
78
 
81
79
 
82
80
  def logout(request):
@@ -117,7 +115,7 @@ def get_user(request):
117
115
 
118
116
  UserModel = get_user_model()
119
117
  try:
120
- user = UserModel._default_manager.get(id=request.session[USER_ID_SESSION_KEY])
118
+ user = UserModel.query.get(id=request.session[USER_ID_SESSION_KEY])
121
119
  except UserModel.DoesNotExist:
122
120
  return None
123
121
 
@@ -0,0 +1,183 @@
1
+ Metadata-Version: 2.4
2
+ Name: plain.auth
3
+ Version: 0.17.0
4
+ Summary: Add users to your app and decide what they can access.
5
+ Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.13
8
+ Requires-Dist: plain-models<1.0.0
9
+ Requires-Dist: plain-sessions<1.0.0
10
+ Requires-Dist: plain<1.0.0
11
+ Description-Content-Type: text/markdown
12
+
13
+ # plain.auth
14
+
15
+ **Add users to your app and decide what they can access.**
16
+
17
+ - [Overview](#overview)
18
+ - [Authentication setup](#authentication-setup)
19
+ - [Settings configuration](#settings-configuration)
20
+ - [Creating a user model](#creating-a-user-model)
21
+ - [Login views](#login-views)
22
+ - [Checking if a user is logged in](#checking-if-a-user-is-logged-in)
23
+ - [Restricting views](#restricting-views)
24
+ - [Installation](#installation)
25
+
26
+ ## Overview
27
+
28
+ The `plain.auth` package provides user authentication and authorization for Plain applications. Here's a basic example of checking if a user is logged in:
29
+
30
+ ```python
31
+ # In a view
32
+ if request.user:
33
+ print(f"Hello, {request.user.email}!")
34
+ else:
35
+ print("You are not logged in.")
36
+ ```
37
+
38
+ And restricting a view to logged-in users:
39
+
40
+ ```python
41
+ from plain.auth.views import AuthViewMixin
42
+ from plain.views import View
43
+
44
+ class ProfileView(AuthViewMixin, View):
45
+ login_required = True
46
+
47
+ def get(self):
48
+ return f"Welcome, {self.request.user.email}!"
49
+ ```
50
+
51
+ ## Authentication setup
52
+
53
+ ### Settings configuration
54
+
55
+ Configure your authentication settings in `app/settings.py`:
56
+
57
+ ```python
58
+ INSTALLED_PACKAGES = [
59
+ # ...
60
+ "plain.auth",
61
+ "plain.sessions",
62
+ "plain.passwords", # Or another auth method
63
+ ]
64
+
65
+ MIDDLEWARE = [
66
+ "plain.sessions.middleware.SessionMiddleware",
67
+ "plain.auth.middleware.AuthenticationMiddleware",
68
+ ]
69
+
70
+ AUTH_USER_MODEL = "users.User"
71
+ AUTH_LOGIN_URL = "login"
72
+ ```
73
+
74
+ ### Creating a user model
75
+
76
+ Create your own user model using `plain create users` or manually:
77
+
78
+ ```python
79
+ # app/users/models.py
80
+ from plain import models
81
+ from plain.passwords.models import PasswordField
82
+
83
+
84
+ class User(models.Model):
85
+ email = models.EmailField()
86
+ password = PasswordField()
87
+ is_admin = models.BooleanField(default=False)
88
+ created_at = models.DateTimeField(auto_now_add=True)
89
+
90
+ def __str__(self):
91
+ return self.email
92
+ ```
93
+
94
+ ### Login views
95
+
96
+ To log users in, you'll need to pair this package with an authentication method:
97
+
98
+ - `plain-passwords` - Username/password authentication
99
+ - `plain-oauth` - OAuth provider authentication
100
+ - `plain-passkeys` (TBD) - WebAuthn/passkey authentication
101
+ - `plain-passlinks` (TBD) - Magic link authentication
102
+
103
+ Example with password authentication:
104
+
105
+ ```python
106
+ # app/urls.py
107
+ from plain.auth.views import LogoutView
108
+ from plain.urls import path
109
+ from plain.passwords.views import PasswordLoginView
110
+
111
+
112
+ class LoginView(PasswordLoginView):
113
+ template_name = "login.html"
114
+
115
+
116
+ urlpatterns = [
117
+ path("logout/", LogoutView, name="logout"),
118
+ path("login/", LoginView, name="login"),
119
+ ]
120
+ ```
121
+
122
+ ## Checking if a user is logged in
123
+
124
+ A `request.user` will either be `None` or point to an instance of your `AUTH_USER_MODEL`.
125
+
126
+ In templates:
127
+
128
+ ```html
129
+ {% if request.user %}
130
+ <p>Hello, {{ request.user.email }}!</p>
131
+ {% else %}
132
+ <p>You are not logged in.</p>
133
+ {% endif %}
134
+ ```
135
+
136
+ In Python code:
137
+
138
+ ```python
139
+ if request.user:
140
+ print(f"Hello, {request.user.email}!")
141
+ else:
142
+ print("You are not logged in.")
143
+ ```
144
+
145
+ ## Restricting views
146
+
147
+ Use the [`AuthViewMixin`](./views.py#AuthViewMixin) to restrict views to logged-in users, admin users, or custom logic:
148
+
149
+ ```python
150
+ from plain.auth.views import AuthViewMixin
151
+ from plain.exceptions import PermissionDenied
152
+ from plain.views import View
153
+
154
+
155
+ class LoggedInView(AuthViewMixin, View):
156
+ login_required = True
157
+
158
+
159
+ class AdminOnlyView(AuthViewMixin, View):
160
+ login_required = True
161
+ admin_required = True
162
+
163
+
164
+ class CustomPermissionView(AuthViewMixin, View):
165
+ def check_auth(self):
166
+ super().check_auth()
167
+ if not self.request.user.is_special:
168
+ raise PermissionDenied("You're not special!")
169
+ ```
170
+
171
+ The [`AuthViewMixin`](./views.py#AuthViewMixin) provides:
172
+
173
+ - `login_required` - Requires a logged-in user
174
+ - `admin_required` - Requires `user.is_admin` to be True
175
+ - `check_auth()` - Override for custom authorization logic
176
+
177
+ ## Installation
178
+
179
+ Install the `plain.auth` package from [PyPI](https://pypi.org/project/plain.auth/):
180
+
181
+ ```bash
182
+ uv add plain.auth
183
+ ```
@@ -1,13 +1,13 @@
1
- plain/auth/CHANGELOG.md,sha256=0P03xkDAmY9b6X2bnifK9ZRB0egyPEVhl8pFzB0VDhk,1174
2
- plain/auth/README.md,sha256=RJ8ry-ukLtLqcjRVAZ5cd1JgCr-JcUTi_9Kkg4kGmHc,2408
1
+ plain/auth/CHANGELOG.md,sha256=1gj4LvlYaXd55IRraPNP9gBbWVa1mjc85kRJyy_KbgU,2162
2
+ plain/auth/README.md,sha256=zPG1AY8pTREu0clHVZDul1fdnv2eqXhMOdwxlnE85sI,3998
3
3
  plain/auth/__init__.py,sha256=Id4ON6caLuZoZhu_kL6aMrwnN3Y8gPGVrVGs_V3ofAE,142
4
4
  plain/auth/default_settings.py,sha256=65VzDn3j61OMn78Lg6Zuds4A8QKzJJ_0G9KoFqAOIRo,466
5
5
  plain/auth/middleware.py,sha256=yiuJ6jg4PW5FpGFEzOzg5SLTjcheRTVPvo4NlmeBKws,1186
6
- plain/auth/sessions.py,sha256=6G9-DGzenzx5yjc6wf7_giPuCo7IqIyc5_n8GLHnFAA,5498
6
+ plain/auth/sessions.py,sha256=ZVNHy_uqz74uJr54AqtlfgAWucCuIbtV6hwm_iMxMQQ,5414
7
7
  plain/auth/test.py,sha256=KfZSiX9S0p3AtCFAS4dUz4ctGIpOmLAGR-8nxAtM2TY,1163
8
8
  plain/auth/utils.py,sha256=eEON0Mo928l-aW5tqBuoTdVke8aP4majxVtAFoLroSE,1280
9
9
  plain/auth/views.py,sha256=_igztEBQKSM4CZro2lvlK0m01eIksqbmyux4w8gY1ks,4095
10
- plain_auth-0.15.0.dist-info/METADATA,sha256=pEpCQM-cGEihqHFhgPzDKxrO7uyKkaRiPCINdD0sUEA,2762
11
- plain_auth-0.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
12
- plain_auth-0.15.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
13
- plain_auth-0.15.0.dist-info/RECORD,,
10
+ plain_auth-0.17.0.dist-info/METADATA,sha256=oQz9ux8GoKp4U-xt5eYfnAXbq-afrw2QO-XSx9DY1S0,4358
11
+ plain_auth-0.17.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
12
+ plain_auth-0.17.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
13
+ plain_auth-0.17.0.dist-info/RECORD,,
@@ -1,128 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: plain.auth
3
- Version: 0.15.0
4
- Summary: User authentication and authorization for Plain.
5
- Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
- License-File: LICENSE
7
- Requires-Python: >=3.11
8
- Requires-Dist: plain-models<1.0.0
9
- Requires-Dist: plain-sessions<1.0.0
10
- Requires-Dist: plain<1.0.0
11
- Description-Content-Type: text/markdown
12
-
13
- # plain.auth
14
-
15
- Add users to your app and define which views they can access.
16
-
17
- To log a user in, you'll want to pair this package with:
18
-
19
- - `plain-passwords`
20
- - `plain-oauth`
21
- - `plain-passkeys` (TBD)
22
- - `plain-passlinks` (TBD)
23
-
24
- ## Installation
25
-
26
- ```python
27
- # app/settings.py
28
- INSTALLED_PACKAGES = [
29
- # ...
30
- "plain.auth",
31
- "plain.sessions",
32
- "plain.passwords",
33
- ]
34
-
35
- MIDDLEWARE = [
36
- "plain.sessions.middleware.SessionMiddleware",
37
- "plain.auth.middleware.AuthenticationMiddleware",
38
- ]
39
-
40
- AUTH_USER_MODEL = "users.User"
41
- AUTH_LOGIN_URL = "login"
42
- ```
43
-
44
- Create your own user model (`plain create users`).
45
-
46
- ```python
47
- # app/users/models.py
48
- from plain import models
49
- from plain.passwords.models import PasswordField
50
-
51
-
52
- class User(models.Model):
53
- email = models.EmailField()
54
- password = PasswordField()
55
- is_admin = models.BooleanField(default=False)
56
- created_at = models.DateTimeField(auto_now_add=True)
57
-
58
- def __str__(self):
59
- return self.email
60
- ```
61
-
62
- Define your URL/view where users can log in.
63
-
64
- ```python
65
- # app/urls.py
66
- from plain.auth.views import LoginView, LogoutView
67
- from plain.urls import include, path
68
- from plain.passwords.views import PasswordLoginView
69
-
70
-
71
- class LoginView(PasswordLoginView):
72
- template_name = "login.html"
73
-
74
-
75
- urlpatterns = [
76
- path("logout/", LogoutView, name="logout"),
77
- path("login/", LoginView, name="login"),
78
- ]
79
- ```
80
-
81
- ## Checking if a user is logged in
82
-
83
- A `request.user` will either be `None` or point to an instance of a your `AUTH_USER_MODEL`.
84
-
85
- So in templates you can do:
86
-
87
- ```html
88
- {% if request.user %}
89
- <p>Hello, {{ request.user.email }}!</p>
90
- {% else %}
91
- <p>You are not logged in.</p>
92
- {% endif %}
93
- ```
94
-
95
- Or in Python:
96
-
97
- ```python
98
- if request.user:
99
- print(f"Hello, {request.user.email}!")
100
- else:
101
- print("You are not logged in.")
102
- ```
103
-
104
- ## Restricting views
105
-
106
- Use the `AuthViewMixin` to restrict views to logged in users, admin users, or custom logic.
107
-
108
- ```python
109
- from plain.auth.views import AuthViewMixin
110
- from plain.exceptions import PermissionDenied
111
- from plain.views import View
112
-
113
-
114
- class LoggedInView(AuthViewMixin, View):
115
- login_required = True
116
-
117
-
118
- class AdminOnlyView(AuthViewMixin, View):
119
- login_required = True
120
- admin_required = True
121
-
122
-
123
- class CustomPermissionView(AuthViewMixin, View):
124
- def check_auth(self):
125
- super().check_auth()
126
- if not self.request.user.is_special:
127
- raise PermissionDenied("You're not special!")
128
- ```