plain.oauth 0.24.1__py3-none-any.whl → 0.25.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/oauth/CHANGELOG.md +22 -0
- plain/oauth/README.md +54 -25
- plain/oauth/models.py +2 -2
- {plain_oauth-0.24.1.dist-info → plain_oauth-0.25.0.dist-info}/METADATA +56 -27
- {plain_oauth-0.24.1.dist-info → plain_oauth-0.25.0.dist-info}/RECORD +7 -7
- {plain_oauth-0.24.1.dist-info → plain_oauth-0.25.0.dist-info}/WHEEL +0 -0
- {plain_oauth-0.24.1.dist-info → plain_oauth-0.25.0.dist-info}/licenses/LICENSE +0 -0
plain/oauth/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# plain-oauth changelog
|
2
2
|
|
3
|
+
## [0.25.0](https://github.com/dropseed/plain/releases/plain-oauth@0.25.0) (2025-08-19)
|
4
|
+
|
5
|
+
### What's changed
|
6
|
+
|
7
|
+
- Removed requirement for manual `{{ csrf_input }}` in OAuth forms - CSRF protection now uses `Sec-Fetch-Site` headers automatically ([9551508](https://github.com/dropseed/plain/commit/955150800c))
|
8
|
+
|
9
|
+
### Upgrade instructions
|
10
|
+
|
11
|
+
- Remove `{{ csrf_input }}` from any OAuth forms in your templates (login, connect, disconnect forms) - CSRF protection is now handled automatically
|
12
|
+
|
13
|
+
## [0.24.2](https://github.com/dropseed/plain/releases/plain-oauth@0.24.2) (2025-08-05)
|
14
|
+
|
15
|
+
### What's changed
|
16
|
+
|
17
|
+
- Updated documentation to use `plain` commands instead of `python manage.py` references ([8071854](https://github.com/dropseed/plain/commit/8071854d61))
|
18
|
+
- Improved README with better structure, table of contents, and more comprehensive examples ([4ebecd1](https://github.com/dropseed/plain/commit/4ebecd1856))
|
19
|
+
- Fixed router setup documentation in URLs section ([48caf10](https://github.com/dropseed/plain/commit/48caf105da))
|
20
|
+
|
21
|
+
### Upgrade instructions
|
22
|
+
|
23
|
+
- No changes required
|
24
|
+
|
3
25
|
## [0.24.1](https://github.com/dropseed/plain/releases/plain-oauth@0.24.1) (2025-07-23)
|
4
26
|
|
5
27
|
### What's changed
|
plain/oauth/README.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
# plain.oauth
|
2
2
|
|
3
|
-
Let users log in with OAuth providers
|
3
|
+
**Let users log in with OAuth providers.**
|
4
|
+
|
5
|
+
- [Overview](#overview)
|
6
|
+
- [Usage](#usage)
|
7
|
+
- [Basic setup example](#basic-setup-example)
|
8
|
+
- [Handling OAuth errors](#handling-oauth-errors)
|
9
|
+
- [Connecting and disconnecting OAuth accounts](#connecting-and-disconnecting-oauth-accounts)
|
10
|
+
- [Using a saved access token](#using-a-saved-access-token)
|
11
|
+
- [Using the Django system check](#using-the-django-system-check)
|
12
|
+
- [FAQs](#faqs)
|
13
|
+
- [Installation](#installation)
|
14
|
+
|
15
|
+
## Overview
|
4
16
|
|
5
17
|
[Watch on YouTube (3 mins) →](https://www.youtube.com/watch?v=UxbxBa6AFsU)
|
6
18
|
|
@@ -17,11 +29,9 @@ There are three OAuth flows that it makes possible:
|
|
17
29
|
|
18
30
|
## Usage
|
19
31
|
|
20
|
-
|
32
|
+
### Basic setup example
|
21
33
|
|
22
|
-
|
23
|
-
pip install plain-oauth
|
24
|
-
```
|
34
|
+
Here's a complete example showing how to set up OAuth login with GitHub:
|
25
35
|
|
26
36
|
Add `plain.oauth` to your `INSTALLED_PACKAGES` in `settings.py`:
|
27
37
|
|
@@ -32,19 +42,24 @@ INSTALLED_PACKAGES = [
|
|
32
42
|
]
|
33
43
|
```
|
34
44
|
|
35
|
-
In your `urls.py`, include `
|
45
|
+
In your `urls.py`, include the [`OAuthRouter`](./urls.py#OAuthRouter):
|
36
46
|
|
37
47
|
```python
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
48
|
+
from plain.oauth.urls import OAuthRouter
|
49
|
+
from plain.urls import Router, include
|
50
|
+
|
51
|
+
class AppRouter(Router):
|
52
|
+
namespace = ""
|
53
|
+
urls = [
|
54
|
+
include("oauth/", OAuthRouter),
|
55
|
+
# ...
|
56
|
+
]
|
42
57
|
```
|
43
58
|
|
44
59
|
Then run migrations:
|
45
60
|
|
46
61
|
```sh
|
47
|
-
|
62
|
+
plain migrate plain.oauth
|
48
63
|
```
|
49
64
|
|
50
65
|
Create a new OAuth provider ([or copy one from our examples](https://github.com/forgepackages/plain-oauth/tree/master/provider_examples)):
|
@@ -56,12 +71,12 @@ import requests
|
|
56
71
|
from plain.oauth.providers import OAuthProvider, OAuthToken, OAuthUser
|
57
72
|
|
58
73
|
|
59
|
-
class
|
60
|
-
authorization_url = "https://
|
74
|
+
class GitHubOAuthProvider(OAuthProvider):
|
75
|
+
authorization_url = "https://github.com/login/oauth/authorize"
|
61
76
|
|
62
77
|
def get_oauth_token(self, *, code, request):
|
63
78
|
response = requests.post(
|
64
|
-
"https://
|
79
|
+
"https://github.com/login/oauth/access_token",
|
65
80
|
headers={
|
66
81
|
"Accept": "application/json",
|
67
82
|
},
|
@@ -79,7 +94,7 @@ class ExampleOAuthProvider(OAuthProvider):
|
|
79
94
|
|
80
95
|
def get_oauth_user(self, *, oauth_token):
|
81
96
|
response = requests.get(
|
82
|
-
"https://
|
97
|
+
"https://api.github.com/user",
|
83
98
|
headers={
|
84
99
|
"Accept": "application/json",
|
85
100
|
"Authorization": f"token {oauth_token.access_token}",
|
@@ -126,7 +141,6 @@ Then add a login button (which is a form using POST rather than a basic link, fo
|
|
126
141
|
```html
|
127
142
|
<h1>Login</h1>
|
128
143
|
<form action="{% url 'oauth:login' 'github' %}" method="post">
|
129
|
-
{{ csrf_input }}
|
130
144
|
<button type="submit">Login with GitHub</button>
|
131
145
|
</form>
|
132
146
|
```
|
@@ -136,8 +150,6 @@ your OAuth callback will be something like `https://example.com/oauth/{provider}
|
|
136
150
|
|
137
151
|
That's pretty much it!
|
138
152
|
|
139
|
-
## Advanced usage
|
140
|
-
|
141
153
|
### Handling OAuth errors
|
142
154
|
|
143
155
|
The most common error you'll run into is if an existing user clicks a login button,
|
@@ -178,7 +190,6 @@ Hello {{ request.user }}!
|
|
178
190
|
<li>
|
179
191
|
{{ connection.provider_key }} [ID: {{ connection.provider_user_id }}]
|
180
192
|
<form action="{% url 'oauth:disconnect' connection.provider_key %}" method="post">
|
181
|
-
{{ csrf_input }}
|
182
193
|
<input type="hidden" name="provider_user_id" value="{{ connection.provider_user_id }}">
|
183
194
|
<button type="submit">Disconnect</button>
|
184
195
|
</form>
|
@@ -192,7 +203,6 @@ Hello {{ request.user }}!
|
|
192
203
|
<li>
|
193
204
|
{{ provider_key}}
|
194
205
|
<form action="{% url 'oauth:connect' provider_key %}" method="post">
|
195
|
-
{{ csrf_input }}
|
196
206
|
<button type="submit">Connect</button>
|
197
207
|
</form>
|
198
208
|
</li>
|
@@ -202,7 +212,7 @@ Hello {{ request.user }}!
|
|
202
212
|
{% endblock %}
|
203
213
|
```
|
204
214
|
|
205
|
-
The `get_provider_keys` function can help populate the list of options:
|
215
|
+
The [`get_provider_keys`](./providers.py#get_provider_keys) function can help populate the list of options:
|
206
216
|
|
207
217
|
```python
|
208
218
|
from plain.oauth.providers import get_provider_keys
|
@@ -241,12 +251,12 @@ This library comes with a Django system check to ensure you don't _remove_ a pro
|
|
241
251
|
You do need to specify the `--database` for this to run when using the check command by itself:
|
242
252
|
|
243
253
|
```sh
|
244
|
-
|
254
|
+
plain check --database default
|
245
255
|
```
|
246
256
|
|
247
257
|
## FAQs
|
248
258
|
|
249
|
-
|
259
|
+
#### How is this different from [Django OAuth libraries](https://djangopackages.org/grids/g/oauth/)?
|
250
260
|
|
251
261
|
The short answer is that _it does less_.
|
252
262
|
|
@@ -265,7 +275,7 @@ and the implications for doing it one way or another.
|
|
265
275
|
The other popular OAuth libraries have similar issues,
|
266
276
|
and I think their _weight_ outweighs their usefulness for 80% of the use cases.
|
267
277
|
|
268
|
-
|
278
|
+
#### Why aren't providers included in the library itself?
|
269
279
|
|
270
280
|
One thing you'll notice is that we don't have a long list of pre-configured providers in this library.
|
271
281
|
Instead, we have some examples (which you can usually just copy, paste, and use) and otherwise encourage you to wire up the provider yourself.
|
@@ -288,7 +298,7 @@ You don't need to try to run changes through us or wait for an upstream update.
|
|
288
298
|
You're welcome to contribute an example to this repo,
|
289
299
|
and there won't be an expectation that it "works perfectly for every use case until the end of time".
|
290
300
|
|
291
|
-
|
301
|
+
#### Redirect/callback URL mismatch in local development?
|
292
302
|
|
293
303
|
If you're doing local development through a proxy/tunnel like [ngrok](https://ngrok.com/),
|
294
304
|
then the callback URL might be automatically built as `http` instead of `https`.
|
@@ -298,3 +308,22 @@ This is the Django setting you're probably looking for:
|
|
298
308
|
```python
|
299
309
|
HTTPS_PROXY_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
300
310
|
```
|
311
|
+
|
312
|
+
## Installation
|
313
|
+
|
314
|
+
Install the `plain.oauth` package from [PyPI](https://pypi.org/project/plain.oauth/):
|
315
|
+
|
316
|
+
```bash
|
317
|
+
uv add plain.oauth
|
318
|
+
```
|
319
|
+
|
320
|
+
After installation, follow the basic setup example in the [Usage](#usage) section above to:
|
321
|
+
|
322
|
+
1. Add `plain.oauth` to your `INSTALLED_PACKAGES`
|
323
|
+
2. Include the OAuth router in your URLs
|
324
|
+
3. Run migrations
|
325
|
+
4. Create an OAuth provider class
|
326
|
+
5. Configure OAuth settings
|
327
|
+
6. Add login buttons to your templates
|
328
|
+
|
329
|
+
For a complete working example, see the [Basic setup example](#basic-setup-example) which shows how to set up GitHub OAuth login.
|
plain/oauth/models.py
CHANGED
@@ -160,7 +160,7 @@ class OAuthConnection(models.Model):
|
|
160
160
|
A system check for ensuring that provider_keys in the database are also present in settings.
|
161
161
|
|
162
162
|
Note that the --database flag is required for this to work:
|
163
|
-
|
163
|
+
plain check --database default
|
164
164
|
"""
|
165
165
|
errors = super().check(**kwargs)
|
166
166
|
|
@@ -175,7 +175,7 @@ class OAuthConnection(models.Model):
|
|
175
175
|
cls.objects.values_list("provider_key", flat=True).distinct()
|
176
176
|
)
|
177
177
|
except (OperationalError, ProgrammingError):
|
178
|
-
# Check runs on
|
178
|
+
# Check runs on plain migrate, and the table may not exist yet
|
179
179
|
# or it may not be installed on the particular database intentionally
|
180
180
|
return errors
|
181
181
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: plain.oauth
|
3
|
-
Version: 0.
|
4
|
-
Summary:
|
3
|
+
Version: 0.25.0
|
4
|
+
Summary: Let users log in with OAuth providers.
|
5
5
|
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
6
6
|
License-Expression: BSD-3-Clause
|
7
7
|
License-File: LICENSE
|
@@ -14,7 +14,19 @@ Description-Content-Type: text/markdown
|
|
14
14
|
|
15
15
|
# plain.oauth
|
16
16
|
|
17
|
-
Let users log in with OAuth providers
|
17
|
+
**Let users log in with OAuth providers.**
|
18
|
+
|
19
|
+
- [Overview](#overview)
|
20
|
+
- [Usage](#usage)
|
21
|
+
- [Basic setup example](#basic-setup-example)
|
22
|
+
- [Handling OAuth errors](#handling-oauth-errors)
|
23
|
+
- [Connecting and disconnecting OAuth accounts](#connecting-and-disconnecting-oauth-accounts)
|
24
|
+
- [Using a saved access token](#using-a-saved-access-token)
|
25
|
+
- [Using the Django system check](#using-the-django-system-check)
|
26
|
+
- [FAQs](#faqs)
|
27
|
+
- [Installation](#installation)
|
28
|
+
|
29
|
+
## Overview
|
18
30
|
|
19
31
|
[Watch on YouTube (3 mins) →](https://www.youtube.com/watch?v=UxbxBa6AFsU)
|
20
32
|
|
@@ -31,11 +43,9 @@ There are three OAuth flows that it makes possible:
|
|
31
43
|
|
32
44
|
## Usage
|
33
45
|
|
34
|
-
|
46
|
+
### Basic setup example
|
35
47
|
|
36
|
-
|
37
|
-
pip install plain-oauth
|
38
|
-
```
|
48
|
+
Here's a complete example showing how to set up OAuth login with GitHub:
|
39
49
|
|
40
50
|
Add `plain.oauth` to your `INSTALLED_PACKAGES` in `settings.py`:
|
41
51
|
|
@@ -46,19 +56,24 @@ INSTALLED_PACKAGES = [
|
|
46
56
|
]
|
47
57
|
```
|
48
58
|
|
49
|
-
In your `urls.py`, include `
|
59
|
+
In your `urls.py`, include the [`OAuthRouter`](./urls.py#OAuthRouter):
|
50
60
|
|
51
61
|
```python
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
62
|
+
from plain.oauth.urls import OAuthRouter
|
63
|
+
from plain.urls import Router, include
|
64
|
+
|
65
|
+
class AppRouter(Router):
|
66
|
+
namespace = ""
|
67
|
+
urls = [
|
68
|
+
include("oauth/", OAuthRouter),
|
69
|
+
# ...
|
70
|
+
]
|
56
71
|
```
|
57
72
|
|
58
73
|
Then run migrations:
|
59
74
|
|
60
75
|
```sh
|
61
|
-
|
76
|
+
plain migrate plain.oauth
|
62
77
|
```
|
63
78
|
|
64
79
|
Create a new OAuth provider ([or copy one from our examples](https://github.com/forgepackages/plain-oauth/tree/master/provider_examples)):
|
@@ -70,12 +85,12 @@ import requests
|
|
70
85
|
from plain.oauth.providers import OAuthProvider, OAuthToken, OAuthUser
|
71
86
|
|
72
87
|
|
73
|
-
class
|
74
|
-
authorization_url = "https://
|
88
|
+
class GitHubOAuthProvider(OAuthProvider):
|
89
|
+
authorization_url = "https://github.com/login/oauth/authorize"
|
75
90
|
|
76
91
|
def get_oauth_token(self, *, code, request):
|
77
92
|
response = requests.post(
|
78
|
-
"https://
|
93
|
+
"https://github.com/login/oauth/access_token",
|
79
94
|
headers={
|
80
95
|
"Accept": "application/json",
|
81
96
|
},
|
@@ -93,7 +108,7 @@ class ExampleOAuthProvider(OAuthProvider):
|
|
93
108
|
|
94
109
|
def get_oauth_user(self, *, oauth_token):
|
95
110
|
response = requests.get(
|
96
|
-
"https://
|
111
|
+
"https://api.github.com/user",
|
97
112
|
headers={
|
98
113
|
"Accept": "application/json",
|
99
114
|
"Authorization": f"token {oauth_token.access_token}",
|
@@ -140,7 +155,6 @@ Then add a login button (which is a form using POST rather than a basic link, fo
|
|
140
155
|
```html
|
141
156
|
<h1>Login</h1>
|
142
157
|
<form action="{% url 'oauth:login' 'github' %}" method="post">
|
143
|
-
{{ csrf_input }}
|
144
158
|
<button type="submit">Login with GitHub</button>
|
145
159
|
</form>
|
146
160
|
```
|
@@ -150,8 +164,6 @@ your OAuth callback will be something like `https://example.com/oauth/{provider}
|
|
150
164
|
|
151
165
|
That's pretty much it!
|
152
166
|
|
153
|
-
## Advanced usage
|
154
|
-
|
155
167
|
### Handling OAuth errors
|
156
168
|
|
157
169
|
The most common error you'll run into is if an existing user clicks a login button,
|
@@ -192,7 +204,6 @@ Hello {{ request.user }}!
|
|
192
204
|
<li>
|
193
205
|
{{ connection.provider_key }} [ID: {{ connection.provider_user_id }}]
|
194
206
|
<form action="{% url 'oauth:disconnect' connection.provider_key %}" method="post">
|
195
|
-
{{ csrf_input }}
|
196
207
|
<input type="hidden" name="provider_user_id" value="{{ connection.provider_user_id }}">
|
197
208
|
<button type="submit">Disconnect</button>
|
198
209
|
</form>
|
@@ -206,7 +217,6 @@ Hello {{ request.user }}!
|
|
206
217
|
<li>
|
207
218
|
{{ provider_key}}
|
208
219
|
<form action="{% url 'oauth:connect' provider_key %}" method="post">
|
209
|
-
{{ csrf_input }}
|
210
220
|
<button type="submit">Connect</button>
|
211
221
|
</form>
|
212
222
|
</li>
|
@@ -216,7 +226,7 @@ Hello {{ request.user }}!
|
|
216
226
|
{% endblock %}
|
217
227
|
```
|
218
228
|
|
219
|
-
The `get_provider_keys` function can help populate the list of options:
|
229
|
+
The [`get_provider_keys`](./providers.py#get_provider_keys) function can help populate the list of options:
|
220
230
|
|
221
231
|
```python
|
222
232
|
from plain.oauth.providers import get_provider_keys
|
@@ -255,12 +265,12 @@ This library comes with a Django system check to ensure you don't _remove_ a pro
|
|
255
265
|
You do need to specify the `--database` for this to run when using the check command by itself:
|
256
266
|
|
257
267
|
```sh
|
258
|
-
|
268
|
+
plain check --database default
|
259
269
|
```
|
260
270
|
|
261
271
|
## FAQs
|
262
272
|
|
263
|
-
|
273
|
+
#### How is this different from [Django OAuth libraries](https://djangopackages.org/grids/g/oauth/)?
|
264
274
|
|
265
275
|
The short answer is that _it does less_.
|
266
276
|
|
@@ -279,7 +289,7 @@ and the implications for doing it one way or another.
|
|
279
289
|
The other popular OAuth libraries have similar issues,
|
280
290
|
and I think their _weight_ outweighs their usefulness for 80% of the use cases.
|
281
291
|
|
282
|
-
|
292
|
+
#### Why aren't providers included in the library itself?
|
283
293
|
|
284
294
|
One thing you'll notice is that we don't have a long list of pre-configured providers in this library.
|
285
295
|
Instead, we have some examples (which you can usually just copy, paste, and use) and otherwise encourage you to wire up the provider yourself.
|
@@ -302,7 +312,7 @@ You don't need to try to run changes through us or wait for an upstream update.
|
|
302
312
|
You're welcome to contribute an example to this repo,
|
303
313
|
and there won't be an expectation that it "works perfectly for every use case until the end of time".
|
304
314
|
|
305
|
-
|
315
|
+
#### Redirect/callback URL mismatch in local development?
|
306
316
|
|
307
317
|
If you're doing local development through a proxy/tunnel like [ngrok](https://ngrok.com/),
|
308
318
|
then the callback URL might be automatically built as `http` instead of `https`.
|
@@ -312,3 +322,22 @@ This is the Django setting you're probably looking for:
|
|
312
322
|
```python
|
313
323
|
HTTPS_PROXY_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
314
324
|
```
|
325
|
+
|
326
|
+
## Installation
|
327
|
+
|
328
|
+
Install the `plain.oauth` package from [PyPI](https://pypi.org/project/plain.oauth/):
|
329
|
+
|
330
|
+
```bash
|
331
|
+
uv add plain.oauth
|
332
|
+
```
|
333
|
+
|
334
|
+
After installation, follow the basic setup example in the [Usage](#usage) section above to:
|
335
|
+
|
336
|
+
1. Add `plain.oauth` to your `INSTALLED_PACKAGES`
|
337
|
+
2. Include the OAuth router in your URLs
|
338
|
+
3. Run migrations
|
339
|
+
4. Create an OAuth provider class
|
340
|
+
5. Configure OAuth settings
|
341
|
+
6. Add login buttons to your templates
|
342
|
+
|
343
|
+
For a complete working example, see the [Basic setup example](#basic-setup-example) which shows how to set up GitHub OAuth login.
|
@@ -1,18 +1,18 @@
|
|
1
|
-
plain/oauth/CHANGELOG.md,sha256=
|
2
|
-
plain/oauth/README.md,sha256=
|
1
|
+
plain/oauth/CHANGELOG.md,sha256=jveYhfTEsrfQtDTQTxz4AE5zpapneZoKaaJl0GF9RcQ,2470
|
2
|
+
plain/oauth/README.md,sha256=m3RRb01DLnoxBtzuYzESSe49OmsZ8P1R5_QsfCSRQgo,11077
|
3
3
|
plain/oauth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
plain/oauth/admin.py,sha256=9DAku8ubV6a_ByFer6UBS0G1cC_gGGHiI_iRP0b78nE,1310
|
5
5
|
plain/oauth/config.py,sha256=0Q4IILBKQbIaxqeL9WRTH5Cka-BO3c3SOj1AdQIAJgc,167
|
6
6
|
plain/oauth/default_settings.py,sha256=dlN1J9vSOjjxPNLp-0qe-cLTqwM4E69ZAx_8lpxMhaM,28
|
7
7
|
plain/oauth/exceptions.py,sha256=yoZsq8XgzstuwbE2ihoet0nzpw_sVZgDrwUauh6hhUs,546
|
8
|
-
plain/oauth/models.py,sha256=
|
8
|
+
plain/oauth/models.py,sha256=iCh_cyi2ajBN2IO8xBIHLyAyjk4OMgB4ziwDQymvwJo,6739
|
9
9
|
plain/oauth/providers.py,sha256=YDftJUMyyfXgsDCkyTNxGwrbwXAowL0Hg6KrwrAN5S0,7793
|
10
10
|
plain/oauth/urls.py,sha256=FYzpQwhvZdcat8n3f7RyA-1Q21finKb8JEyakSOjXXg,696
|
11
11
|
plain/oauth/views.py,sha256=J2NCa37YediBTi82CfRlmsb45hFT6gWN6zMaFHhsDMM,2410
|
12
12
|
plain/oauth/migrations/0001_initial.py,sha256=0NjfF7F3szhUXkpK3JvN10Xkat1QR-VvnX6Oed9iFmo,1940
|
13
13
|
plain/oauth/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
14
|
plain/oauth/templates/oauth/callback.html,sha256=4CJG0oAN0xYjw2IPkjaL7B4hwlf9um9LI4CTu50E-yE,173
|
15
|
-
plain_oauth-0.
|
16
|
-
plain_oauth-0.
|
17
|
-
plain_oauth-0.
|
18
|
-
plain_oauth-0.
|
15
|
+
plain_oauth-0.25.0.dist-info/METADATA,sha256=B3Bf2zRjB8LkHautDtWJ9RH7QMubpb-gt1ebvfc4H5s,11482
|
16
|
+
plain_oauth-0.25.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
17
|
+
plain_oauth-0.25.0.dist-info/licenses/LICENSE,sha256=cvKM3OlqHx3ijD6e34zsSUkPvzl-ya3Dd63A6EHL94U,1500
|
18
|
+
plain_oauth-0.25.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|