django-gauth 0.1.2__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.
- django_gauth-0.1.2/LICENSE +21 -0
- django_gauth-0.1.2/PKG-INFO +139 -0
- django_gauth-0.1.2/README.md +111 -0
- django_gauth-0.1.2/pypi.README.md +60 -0
- django_gauth-0.1.2/pyproject.toml +290 -0
- django_gauth-0.1.2/setup.cfg +4 -0
- django_gauth-0.1.2/src/django_gauth/__init__.py +5 -0
- django_gauth-0.1.2/src/django_gauth/admin.py +24 -0
- django_gauth-0.1.2/src/django_gauth/apps.py +9 -0
- django_gauth-0.1.2/src/django_gauth/defaults.py +8 -0
- django_gauth-0.1.2/src/django_gauth/py.typed +0 -0
- django_gauth-0.1.2/src/django_gauth/urls.py +17 -0
- django_gauth-0.1.2/src/django_gauth/utilities.py +73 -0
- django_gauth-0.1.2/src/django_gauth/views.py +149 -0
- django_gauth-0.1.2/src/django_gauth.egg-info/PKG-INFO +139 -0
- django_gauth-0.1.2/src/django_gauth.egg-info/SOURCES.txt +17 -0
- django_gauth-0.1.2/src/django_gauth.egg-info/dependency_links.txt +1 -0
- django_gauth-0.1.2/src/django_gauth.egg-info/requires.txt +25 -0
- django_gauth-0.1.2/src/django_gauth.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ankit Yadav
|
|
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,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django_gauth
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: A Django app for providing the Google's discovery based Oauth2 authentication mechanism is HTTP/HTTPS oriented Django Servers/Projects.
|
|
5
|
+
Author-email: Ankit Kumar <ankit.kumar05@telusdigital.com>, Ankit Yadav <ankit8290@gmail.com>
|
|
6
|
+
Maintainer-email: Ankit yadav <ankit8290@gmail.com>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2025 Ankit Yadav
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Documentation, https://masterpiece93.github.io/django-gauth/
|
|
30
|
+
Project-URL: Repository, https://github.com/masterPiece93/django-gauth
|
|
31
|
+
Project-URL: Changelog, https://github.com/masterPiece93/django-gauth/releases
|
|
32
|
+
Keywords: django_gauth,google,oauth2,auth
|
|
33
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
34
|
+
Classifier: Environment :: Web Environment
|
|
35
|
+
Classifier: Framework :: Django
|
|
36
|
+
Classifier: Framework :: Django :: 3.1
|
|
37
|
+
Classifier: Intended Audience :: Developers
|
|
38
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
39
|
+
Classifier: Operating System :: OS Independent
|
|
40
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
45
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
46
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
47
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
48
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
49
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
50
|
+
Classifier: Topic :: Utilities
|
|
51
|
+
Classifier: Typing :: Typed
|
|
52
|
+
Requires-Python: >=3.9
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
License-File: LICENSE
|
|
55
|
+
Requires-Dist: Django>=3.1
|
|
56
|
+
Requires-Dist: google-api-python-client
|
|
57
|
+
Requires-Dist: google-auth-oauthlib
|
|
58
|
+
Requires-Dist: mypy>=1.18.1
|
|
59
|
+
Provides-Extra: dev
|
|
60
|
+
Requires-Dist: build==1.2.1; extra == "dev"
|
|
61
|
+
Requires-Dist: nox==2024.4.15; extra == "dev"
|
|
62
|
+
Requires-Dist: twine==5.1.1; extra == "dev"
|
|
63
|
+
Requires-Dist: check-wheel-contents; extra == "dev"
|
|
64
|
+
Requires-Dist: mypy; extra == "dev"
|
|
65
|
+
Requires-Dist: graphviz; extra == "dev"
|
|
66
|
+
Requires-Dist: pipdeptree; extra == "dev"
|
|
67
|
+
Provides-Extra: lint
|
|
68
|
+
Requires-Dist: codespell>=2.2.4; extra == "lint"
|
|
69
|
+
Requires-Dist: ruff; extra == "lint"
|
|
70
|
+
Requires-Dist: vulture; extra == "lint"
|
|
71
|
+
Requires-Dist: tomli; extra == "lint"
|
|
72
|
+
Requires-Dist: validate-pyproject[all]; extra == "lint"
|
|
73
|
+
Requires-Dist: isort; extra == "lint"
|
|
74
|
+
Requires-Dist: black; extra == "lint"
|
|
75
|
+
Requires-Dist: mypy; extra == "lint"
|
|
76
|
+
Requires-Dist: pylint; extra == "lint"
|
|
77
|
+
Requires-Dist: pylint-actions; extra == "lint"
|
|
78
|
+
Dynamic: license-file
|
|
79
|
+
|
|
80
|
+
# Google Auth <sup>[ Django ]<sup>
|
|
81
|
+
|
|
82
|
+
 [](https://github.com/masterPiece93/django-gauth/actions/workflows/pages/pages-build-deployment) [](https://github.com/masterPiece93/django-gauth/actions/workflows/pylint.yml)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
> [Official Documentation](https://masterpiece93.github.io/django-gauth/)
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
<!-- Implement Carousal -->
|
|
90
|
+
|
|
91
|
+
| Source | Command |
|
|
92
|
+
| ------ | ------- |
|
|
93
|
+
| **GitHub** | ```pip install -e git+https://github.com/masterPiece93/django-gauth.git#egg=django_gauth```|
|
|
94
|
+
| **PyPi**| ```pip install django-gauth``` |
|
|
95
|
+
|
|
96
|
+
## Quickstart
|
|
97
|
+
|
|
98
|
+
1. add the app name : `django_gauth` in **INSTALLED_APPS** entry of you project ( in settings.py file )
|
|
99
|
+
2. add required configuration variables ( in *settings.py* file )
|
|
100
|
+
```python
|
|
101
|
+
# settings.py
|
|
102
|
+
GOOGLE_CLIENT_ID= env("GOOGLE_CLIENT_ID") # << set according to your oauth2 client
|
|
103
|
+
GOOGLE_CLIENT_SECRET= env("GOOGLE_CLIENT_SECRET") # << set according to your oauth2 client
|
|
104
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL= None # defaults to `<host>/gauth/`
|
|
105
|
+
CREDENTIALS_SESSION_KEY_NAME= "credentials" # defaults to `credentials`
|
|
106
|
+
STATE_KEY_NAME= "oauth_state" # defaults to `oauth_state`
|
|
107
|
+
SCOPE= [
|
|
108
|
+
"https://www.googleapis.com/auth/userinfo.email" # always preffered
|
|
109
|
+
,"https://www.googleapis.com/auth/userinfo.profile" # always preffered
|
|
110
|
+
,"openid" # always preffered
|
|
111
|
+
,"https://www.googleapis.com/auth/drive" # based on your usage
|
|
112
|
+
]
|
|
113
|
+
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # strictly for local-development only
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- `os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'` directs the server to accept in-secure (http) connections .
|
|
117
|
+
|
|
118
|
+
3. configure auth urls ( in *urls.py* file of root )
|
|
119
|
+
```python
|
|
120
|
+
# urls.py
|
|
121
|
+
from django.contrib import admin
|
|
122
|
+
from django.urls import path, include
|
|
123
|
+
|
|
124
|
+
urlpatterns = [
|
|
125
|
+
path('admin/', admin.site.urls),
|
|
126
|
+
path('gauth/', include('django_gauth.urls')),
|
|
127
|
+
|
|
128
|
+
# add your other app's urls
|
|
129
|
+
# ...
|
|
130
|
+
|
|
131
|
+
]
|
|
132
|
+
```
|
|
133
|
+
* NOTE :
|
|
134
|
+
useually all servers ( **wsgi**, **asgi**, **uWsgi**) runs default on `http://127.0.0.1:PORT/` , hence always take care to set the redirect endpoints in your google oauth2 client app in accordance with *127.0.0.1* , don't mistake to consider *localhost* , *0.0.0.0* and *127.0.0.1* as the same thing while dealing with redirect uri's .
|
|
135
|
+
- For example : suppose you have set `http://localhost:PORT/gauth/google-callback` as your redirect uri , then take note of running your django app on localhost:PORT only !!
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
<br>
|
|
139
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Google Auth <sup>[ Django ]<sup>
|
|
2
|
+
|
|
3
|
+
 [](https://github.com/masterPiece93/django-gauth/actions/workflows/pages/pages-build-deployment) [](https://github.com/masterPiece93/django-gauth/actions/workflows/pylint.yml)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
* [Official Documentation](https://masterpiece93.github.io/django-gauth/)
|
|
7
|
+
|
|
8
|
+
## Developer Zone
|
|
9
|
+
|
|
10
|
+
> [Developer README](./dev.README.md)
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
<!-- Implement Carousal -->
|
|
15
|
+
|
|
16
|
+
from GitHub :
|
|
17
|
+
```sh
|
|
18
|
+
# Editable Installation (for Development)
|
|
19
|
+
pip install -e git+https://github.com/xavient/django-gauth.git#egg=django_gauth
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
# Main Branch (Latest Version)
|
|
24
|
+
pip install git+https://github.com/xavient/django-gauth.git
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
from PyPi
|
|
28
|
+
```sh
|
|
29
|
+
pip install django-gauth
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
from test PyPi
|
|
33
|
+
```sh
|
|
34
|
+
pip install -i https://test.pypi.org/simple/ django-gauth
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quickstart
|
|
38
|
+
|
|
39
|
+
1. add the app name : `django_gauth` in **INSTALLED_APPS** entry of you project ( in settings.py file )
|
|
40
|
+
2. add required configuration variables ( in *settings.py* file )
|
|
41
|
+
```python
|
|
42
|
+
# settings.py
|
|
43
|
+
GOOGLE_CLIENT_ID= env("GOOGLE_CLIENT_ID") # << set according to your oauth2 client
|
|
44
|
+
GOOGLE_CLIENT_SECRET= env("GOOGLE_CLIENT_SECRET") # << set according to your oauth2 client
|
|
45
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL= None # defaults to `<host>/gauth/`
|
|
46
|
+
CREDENTIALS_SESSION_KEY_NAME= "credentials" # defaults to `credentials`
|
|
47
|
+
STATE_KEY_NAME= "oauth_state" # defaults to `oauth_state`
|
|
48
|
+
SCOPE= [
|
|
49
|
+
"https://www.googleapis.com/auth/userinfo.email" # always preffered
|
|
50
|
+
,"https://www.googleapis.com/auth/userinfo.profile" # always preffered
|
|
51
|
+
,"openid" # always preffered
|
|
52
|
+
,"https://www.googleapis.com/auth/drive" # based on your usage
|
|
53
|
+
]
|
|
54
|
+
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # strictly for local-development only
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- `os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'` directs the server to accept in-secure (http) connections .
|
|
58
|
+
|
|
59
|
+
3. configure auth urls ( in *urls.py* file of root )
|
|
60
|
+
```python
|
|
61
|
+
# urls.py
|
|
62
|
+
from django.contrib import admin
|
|
63
|
+
from django.urls import path, include
|
|
64
|
+
|
|
65
|
+
urlpatterns = [
|
|
66
|
+
path('admin/', admin.site.urls),
|
|
67
|
+
path('gauth/', include('django_gauth.urls')),
|
|
68
|
+
|
|
69
|
+
# add your other app's urls
|
|
70
|
+
# ...
|
|
71
|
+
|
|
72
|
+
]
|
|
73
|
+
```
|
|
74
|
+
> NOTE : useually all servers ( wsgi, asgi, uWsgi) runs default on `http://127.0.0.1:PORT/` , hence always take care to set the redirect endpoints in your google oauth2 client app in accordance with 127.0.0.1 , don't mistake to consider localhost , 0.0.0.0 and 127.0.0.1 as same while dealing with redirect uri's . For example : suppose you have set `http://localhost:PORT/gauth/google-callback` as your redirect uri , then take note of running your django app on localhost only !!
|
|
75
|
+
|
|
76
|
+
> NOTE :
|
|
77
|
+
---
|
|
78
|
+
<br>
|
|
79
|
+
|
|
80
|
+
### Important Points <sup> <small>To Be Noted</small> </sup>
|
|
81
|
+
|
|
82
|
+
for production applications , that are working on http**s** , must ensure the following settings for django to be http**s** aware :
|
|
83
|
+
```sh
|
|
84
|
+
USE_X_FORWARDED_HOST = True
|
|
85
|
+
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Your reverse proxy should add the X-Forwarded-Proto: https header to requests forwarded to Django.
|
|
89
|
+
Configure your reverse proxy to set X-Forwarded-Proto header ( Nginx Example ):
|
|
90
|
+
```sh
|
|
91
|
+
server {
|
|
92
|
+
listen 80;
|
|
93
|
+
server_name yourdomain.com;
|
|
94
|
+
return 301 https://$host$request_uri;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
server {
|
|
98
|
+
listen 443 ssl;
|
|
99
|
+
server_name yourdomain.com;
|
|
100
|
+
|
|
101
|
+
# ... SSL configuration ...
|
|
102
|
+
|
|
103
|
+
location / {
|
|
104
|
+
proxy_pass http://your_django_app_server;
|
|
105
|
+
proxy_set_header Host $host;
|
|
106
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
107
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
108
|
+
proxy_set_header X-Forwarded-Proto https; # Crucial line
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Google Auth <sup>[ Django ]<sup>
|
|
2
|
+
|
|
3
|
+
 [](https://github.com/masterPiece93/django-gauth/actions/workflows/pages/pages-build-deployment) [](https://github.com/masterPiece93/django-gauth/actions/workflows/pylint.yml)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
> [Official Documentation](https://masterpiece93.github.io/django-gauth/)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
<!-- Implement Carousal -->
|
|
11
|
+
|
|
12
|
+
| Source | Command |
|
|
13
|
+
| ------ | ------- |
|
|
14
|
+
| **GitHub** | ```pip install -e git+https://github.com/masterPiece93/django-gauth.git#egg=django_gauth```|
|
|
15
|
+
| **PyPi**| ```pip install django-gauth``` |
|
|
16
|
+
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
19
|
+
1. add the app name : `django_gauth` in **INSTALLED_APPS** entry of you project ( in settings.py file )
|
|
20
|
+
2. add required configuration variables ( in *settings.py* file )
|
|
21
|
+
```python
|
|
22
|
+
# settings.py
|
|
23
|
+
GOOGLE_CLIENT_ID= env("GOOGLE_CLIENT_ID") # << set according to your oauth2 client
|
|
24
|
+
GOOGLE_CLIENT_SECRET= env("GOOGLE_CLIENT_SECRET") # << set according to your oauth2 client
|
|
25
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL= None # defaults to `<host>/gauth/`
|
|
26
|
+
CREDENTIALS_SESSION_KEY_NAME= "credentials" # defaults to `credentials`
|
|
27
|
+
STATE_KEY_NAME= "oauth_state" # defaults to `oauth_state`
|
|
28
|
+
SCOPE= [
|
|
29
|
+
"https://www.googleapis.com/auth/userinfo.email" # always preffered
|
|
30
|
+
,"https://www.googleapis.com/auth/userinfo.profile" # always preffered
|
|
31
|
+
,"openid" # always preffered
|
|
32
|
+
,"https://www.googleapis.com/auth/drive" # based on your usage
|
|
33
|
+
]
|
|
34
|
+
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # strictly for local-development only
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'` directs the server to accept in-secure (http) connections .
|
|
38
|
+
|
|
39
|
+
3. configure auth urls ( in *urls.py* file of root )
|
|
40
|
+
```python
|
|
41
|
+
# urls.py
|
|
42
|
+
from django.contrib import admin
|
|
43
|
+
from django.urls import path, include
|
|
44
|
+
|
|
45
|
+
urlpatterns = [
|
|
46
|
+
path('admin/', admin.site.urls),
|
|
47
|
+
path('gauth/', include('django_gauth.urls')),
|
|
48
|
+
|
|
49
|
+
# add your other app's urls
|
|
50
|
+
# ...
|
|
51
|
+
|
|
52
|
+
]
|
|
53
|
+
```
|
|
54
|
+
* NOTE :
|
|
55
|
+
useually all servers ( **wsgi**, **asgi**, **uWsgi**) runs default on `http://127.0.0.1:PORT/` , hence always take care to set the redirect endpoints in your google oauth2 client app in accordance with *127.0.0.1* , don't mistake to consider *localhost* , *0.0.0.0* and *127.0.0.1* as the same thing while dealing with redirect uri's .
|
|
56
|
+
- For example : suppose you have set `http://localhost:PORT/gauth/google-callback` as your redirect uri , then take note of running your django app on localhost:PORT only !!
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
<br>
|
|
60
|
+
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "django_gauth"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Ankit Kumar", email = "ankit.kumar05@telusdigital.com"},
|
|
10
|
+
{name = "Ankit Yadav", email = "ankit8290@gmail.com"},
|
|
11
|
+
]
|
|
12
|
+
maintainers = [
|
|
13
|
+
{name = "Ankit yadav", email="ankit8290@gmail.com"},
|
|
14
|
+
]
|
|
15
|
+
description = "A Django app for providing the Google's discovery based Oauth2 authentication mechanism is HTTP/HTTPS oriented Django Servers/Projects."
|
|
16
|
+
readme = "pypi.README.md"
|
|
17
|
+
license = {file = "LICENSE"}
|
|
18
|
+
keywords = ["django_gauth", "google", "oauth2", "auth"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 5 - Production/Stable",
|
|
21
|
+
"Environment :: Web Environment",
|
|
22
|
+
"Framework :: Django",
|
|
23
|
+
"Framework :: Django :: 3.1",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"License :: OSI Approved :: MIT License",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
28
|
+
"Programming Language :: Python :: 3.9",
|
|
29
|
+
"Programming Language :: Python :: 3.10",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
33
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
34
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
35
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
36
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
37
|
+
"Topic :: Utilities",
|
|
38
|
+
"Typing :: Typed"
|
|
39
|
+
]
|
|
40
|
+
requires-python = ">=3.9"
|
|
41
|
+
dependencies = [
|
|
42
|
+
"Django>=3.1",
|
|
43
|
+
"google-api-python-client",
|
|
44
|
+
"google-auth-oauthlib",
|
|
45
|
+
"mypy>=1.18.1",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
#Homepage = "/"
|
|
50
|
+
Documentation = "https://masterpiece93.github.io/django-gauth/"
|
|
51
|
+
Repository = "https://github.com/masterPiece93/django-gauth"
|
|
52
|
+
Changelog = "https://github.com/masterPiece93/django-gauth/releases"
|
|
53
|
+
|
|
54
|
+
[project.optional-dependencies]
|
|
55
|
+
dev = [
|
|
56
|
+
|
|
57
|
+
# building package
|
|
58
|
+
"build==1.2.1",
|
|
59
|
+
|
|
60
|
+
# multiple python platforms testing
|
|
61
|
+
"nox==2024.4.15",
|
|
62
|
+
|
|
63
|
+
# PyPi Hosting
|
|
64
|
+
"twine==5.1.1",
|
|
65
|
+
|
|
66
|
+
# Build Verification
|
|
67
|
+
"check-wheel-contents",
|
|
68
|
+
|
|
69
|
+
# Typechecking
|
|
70
|
+
"mypy",
|
|
71
|
+
|
|
72
|
+
# Analyzing dependencies
|
|
73
|
+
"graphviz",
|
|
74
|
+
"pipdeptree",
|
|
75
|
+
]
|
|
76
|
+
lint = [
|
|
77
|
+
# checks for spelling mistakes
|
|
78
|
+
"codespell>=2.2.4",
|
|
79
|
+
|
|
80
|
+
# ruff linter checks for issues and potential bugs
|
|
81
|
+
"ruff",
|
|
82
|
+
|
|
83
|
+
# checks for unused code
|
|
84
|
+
"vulture",
|
|
85
|
+
|
|
86
|
+
# required for codespell to parse pyproject.toml
|
|
87
|
+
"tomli",
|
|
88
|
+
|
|
89
|
+
# validation of pyproject.toml
|
|
90
|
+
"validate-pyproject[all]",
|
|
91
|
+
|
|
92
|
+
# automatic sorting of imports
|
|
93
|
+
"isort",
|
|
94
|
+
|
|
95
|
+
# automatic code formatting to follow a consistent style
|
|
96
|
+
"black",
|
|
97
|
+
|
|
98
|
+
# Typechecking
|
|
99
|
+
"mypy",
|
|
100
|
+
|
|
101
|
+
# logical linting
|
|
102
|
+
"pylint",
|
|
103
|
+
"pylint-actions",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
# Tools
|
|
107
|
+
# -----
|
|
108
|
+
|
|
109
|
+
# PDM example
|
|
110
|
+
[tool.pdm]
|
|
111
|
+
distribution = true
|
|
112
|
+
|
|
113
|
+
[tool.pdm.scripts]
|
|
114
|
+
isort = "isort src/django_gauth"
|
|
115
|
+
black = "black src/django_gauth"
|
|
116
|
+
format = {composite = ["isort", "black"]}
|
|
117
|
+
check_isort = "isort --check src/django_gauth"
|
|
118
|
+
check_black = "black --check src/django_gauth"
|
|
119
|
+
vulture = "vulture --min-confidence 100 src/django_gauth"
|
|
120
|
+
ruff = "ruff check --show-files src/django_gauth"
|
|
121
|
+
fix = "ruff check --fix src/django_gauth"
|
|
122
|
+
# codespell = "codespell --toml ./pyproject.toml" # Not Working Properly
|
|
123
|
+
lint = {composite = ["vulture", "ruff", "check_isort", "check_black"]}
|
|
124
|
+
mypy = "mypy src/"
|
|
125
|
+
pylint = "pylint -f actions src/"
|
|
126
|
+
check_build = "check-wheel-contents dist/"
|
|
127
|
+
|
|
128
|
+
[tool.black]
|
|
129
|
+
line-length = 88
|
|
130
|
+
# If you need to exclude directories from being reformatted by black
|
|
131
|
+
# force-exclude = '''
|
|
132
|
+
# (
|
|
133
|
+
# somedirname
|
|
134
|
+
# | dirname
|
|
135
|
+
# | filename\.py
|
|
136
|
+
# )
|
|
137
|
+
# '''
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
[tool.isort]
|
|
141
|
+
profile = "black"
|
|
142
|
+
known_first_party = ["acme"]
|
|
143
|
+
# If you need to exclude files from having their imports sorted
|
|
144
|
+
extend_skip_glob = [
|
|
145
|
+
"acme/somefile.py",
|
|
146
|
+
"acme/somedir/*",
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# https://beta.ruff.rs/docs
|
|
151
|
+
[tool.ruff]
|
|
152
|
+
line-length = 99
|
|
153
|
+
|
|
154
|
+
# Rules: https://beta.ruff.rs/docs/rules
|
|
155
|
+
# If you violate a rule, lookup the rule on the Rules page in ruff docs.
|
|
156
|
+
# Many rules have links you can click with a explanation of the rule and how to fix it.
|
|
157
|
+
# If there isn't a link, go to the project the rule was source from (e.g. flake8-bugbear)
|
|
158
|
+
# and review it's docs for the corresponding rule.
|
|
159
|
+
# If you're still confused, ask a fellow developer for assistance.
|
|
160
|
+
# You can also run "ruff rule <rule>" to explain a rule on the command line, without a browser or internet access.
|
|
161
|
+
select = [
|
|
162
|
+
"E", # pycodestyle
|
|
163
|
+
"F", # Pyflakes
|
|
164
|
+
"W", # Warning
|
|
165
|
+
"B", # flake8-bugbear
|
|
166
|
+
"A", # flake8-builtins
|
|
167
|
+
"C4", # flake8-comprehensions
|
|
168
|
+
"T10", # flake8-debugger
|
|
169
|
+
"EXE", # flake8-executable,
|
|
170
|
+
"ISC", # flake8-implicit-str-concat
|
|
171
|
+
"G", # flake8-logging-format
|
|
172
|
+
"PIE", # flake8-pie
|
|
173
|
+
"T20", # flake8-print
|
|
174
|
+
"PT", # flake8-pytest-style
|
|
175
|
+
"RSE", # flake8-raise
|
|
176
|
+
"RET", # flake8-return
|
|
177
|
+
"TID", # flake8-tidy-imports
|
|
178
|
+
"ARG", # flake8-unused-arguments
|
|
179
|
+
"PGH", # pygrep-hooks
|
|
180
|
+
"PLC", # Pylint Convention
|
|
181
|
+
"PLE", # Pylint Errors
|
|
182
|
+
"PLW", # Pylint Warnings
|
|
183
|
+
"RUF", # Ruff-specific rules
|
|
184
|
+
|
|
185
|
+
# ** Things to potentially enable in the future **
|
|
186
|
+
# DTZ requires all usage of datetime module to have timezone-aware
|
|
187
|
+
# objects (so have a tz argument or be explicitly UTC).
|
|
188
|
+
# "DTZ", # flake8-datetimez
|
|
189
|
+
# "PTH", # flake8-use-pathlib
|
|
190
|
+
# "SIM", # flake8-simplify
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
# Files to exclude from linting
|
|
194
|
+
extend-exclude = [
|
|
195
|
+
"*.pyc",
|
|
196
|
+
"__pycache__",
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
# Linting error codes to ignore
|
|
200
|
+
ignore = [
|
|
201
|
+
"F403", # unable to detect undefined names from star imports
|
|
202
|
+
"F405", # undefined locals from star imports
|
|
203
|
+
"W605", # invalid escape sequence
|
|
204
|
+
"A003", # shadowing python builtins
|
|
205
|
+
"RET505", # unnecessary 'else' after 'return' statement
|
|
206
|
+
"RET504", # Unnecessary variable assignment before return statement
|
|
207
|
+
"RET507", # Unnecessary {branch} after continue statement
|
|
208
|
+
"PT011", # pytest-raises-too-broad
|
|
209
|
+
"PT012", # pytest.raises() block should contain a single simple statement
|
|
210
|
+
"PLW0603", # Using the global statement to update is discouraged
|
|
211
|
+
"PLW2901", # for loop variable overwritten by assignment target
|
|
212
|
+
"G004", # Logging statement uses f-string
|
|
213
|
+
"PIE790", # no-unnecessary-pass
|
|
214
|
+
"PIE810", # multiple-starts-ends-with
|
|
215
|
+
"PGH003", # Use specific rule codes when ignoring type issues
|
|
216
|
+
"PLC1901", # compare-to-empty-string
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
# Linting error codes to ignore on a per-file basis
|
|
220
|
+
[tool.ruff.per-file-ignores]
|
|
221
|
+
"__init__.py" = ["F401", "E501"]
|
|
222
|
+
"acme/somefile.py" = ["E402", "E501"]
|
|
223
|
+
"acme/somedir/*" = ["E501"]
|
|
224
|
+
|
|
225
|
+
# MyPy
|
|
226
|
+
[tool.mypy]
|
|
227
|
+
python_version = "3.12"
|
|
228
|
+
follow_imports = "skip"
|
|
229
|
+
ignore_missing_imports = true
|
|
230
|
+
files = "src" # directory mypy should analyze
|
|
231
|
+
exclude = [ # Directories to exclude from mypy's analysis
|
|
232
|
+
"acme/somedir",
|
|
233
|
+
"acme/somefile\\.py",
|
|
234
|
+
"dirname",
|
|
235
|
+
"src/django_gauth/admin\\.py"
|
|
236
|
+
]
|
|
237
|
+
|
|
238
|
+
[[tool.mypy.overrides]]
|
|
239
|
+
module = "django_gauth.*"
|
|
240
|
+
ignore_missing_imports = false
|
|
241
|
+
disallow_untyped_defs = true
|
|
242
|
+
check_untyped_defs = true
|
|
243
|
+
|
|
244
|
+
# Configuration for pytest
|
|
245
|
+
# https://docs.pytest.org/en/latest/reference/customize.html#pyproject-toml
|
|
246
|
+
[tool.pytest.ini_options]
|
|
247
|
+
testpaths = "tests" # directory containing your tests
|
|
248
|
+
norecursedirs = [
|
|
249
|
+
".vscode",
|
|
250
|
+
"__pycache__"
|
|
251
|
+
]
|
|
252
|
+
# Warnings that should be ignored
|
|
253
|
+
filterwarnings = [
|
|
254
|
+
"ignore::DeprecationWarning"
|
|
255
|
+
]
|
|
256
|
+
# custom markers that can be used using pytest.mark
|
|
257
|
+
markers = [
|
|
258
|
+
"slow: lower-importance tests that take an excessive amount of time",
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# Configuration for coverage.py
|
|
263
|
+
[tool.coverage.run]
|
|
264
|
+
# files or directories to exclude from coverage calculations
|
|
265
|
+
omit = [
|
|
266
|
+
'acme/somedir/*',
|
|
267
|
+
'acme/somefile.py',
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
# Configuration for vulture
|
|
272
|
+
[tool.vulture]
|
|
273
|
+
# Files or directories to exclude from vulture
|
|
274
|
+
# The syntax is a little funky
|
|
275
|
+
exclude = [
|
|
276
|
+
"somedir",
|
|
277
|
+
"*somefile.py",
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
# Configuration for Pylint
|
|
281
|
+
[tool.pylint.main]
|
|
282
|
+
load-plugins = "pylint_actions" # Optional, for GitHub Actions annotations
|
|
283
|
+
disable = [
|
|
284
|
+
"C0114", # Missing module docstring
|
|
285
|
+
"C0116", # Missing function or method docstring
|
|
286
|
+
]
|
|
287
|
+
max-line-length = 100
|
|
288
|
+
|
|
289
|
+
[tool.pylint.messages_control]
|
|
290
|
+
good-names = ["i", "j", "k", "ex", "Run", "_"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import pprint
|
|
2
|
+
from django.contrib import admin # pylint: disable=E0401
|
|
3
|
+
from django.contrib.sessions.models import Session # pylint: disable=E0401
|
|
4
|
+
|
|
5
|
+
# pylint: disable=R0903
|
|
6
|
+
class SessionAdmin(admin.ModelAdmin):
|
|
7
|
+
"""
|
|
8
|
+
Session information on admin panel
|
|
9
|
+
"""
|
|
10
|
+
list_display = ["session_key", "_session_data", "expire_date"]
|
|
11
|
+
readonly_fields = ["_session_data"]
|
|
12
|
+
exclude = [
|
|
13
|
+
"session_data"
|
|
14
|
+
] # This line ensures that encoded session in not shown .
|
|
15
|
+
# Comment this if you want to see the encoded session data as well .
|
|
16
|
+
|
|
17
|
+
def _session_data(self, obj):
|
|
18
|
+
|
|
19
|
+
return pprint.pformat(obj.get_decoded()).replace("\n", "<br>\n")
|
|
20
|
+
|
|
21
|
+
_session_data.allow_tags = True
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
admin.site.register(Session, SessionAdmin)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from typing import Final, Optional
|
|
2
|
+
|
|
3
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL: Final[Optional[str]] = (
|
|
4
|
+
None # auto selects django_gauth > index.html
|
|
5
|
+
)
|
|
6
|
+
CREDENTIALS_SESSION_KEY_NAME: Final[str] = "credentials"
|
|
7
|
+
STATE_KEY_NAME: Final[str] = "oauth_state"
|
|
8
|
+
FINAL_REDIRECT_KEY_NAME: Final[str] = "final_redirect"
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# urls
|
|
2
|
+
|
|
3
|
+
from django.urls import path # pylint: disable=E0401
|
|
4
|
+
|
|
5
|
+
from . import views
|
|
6
|
+
|
|
7
|
+
# this key is used when you refer an endpoint by `reverse`
|
|
8
|
+
app_name = "django_gauth" # pylint: disable=C0103
|
|
9
|
+
|
|
10
|
+
urlpatterns = [
|
|
11
|
+
path("", views.index, name="index"),
|
|
12
|
+
path("login/", views.login, name="login"),
|
|
13
|
+
path("login-callback", views.callback, name="callback"),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
# NOTE : `/` at the end of the route will be taken in cosideration while redirected .
|
|
17
|
+
# # if you have strict slashes issues , do take care where to put the `/` or not .
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Any, Dict, Tuple, Union
|
|
3
|
+
from urllib.parse import urlparse
|
|
4
|
+
|
|
5
|
+
from django.conf import Settings, settings # pylint: disable=E0401
|
|
6
|
+
from google.oauth2.credentials import Credentials # pylint: disable=E0401
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"credentials_to_dict",
|
|
10
|
+
"has_epoch_time_passed",
|
|
11
|
+
"check_gauth_authentication",
|
|
12
|
+
"is_valid_google_url",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def credentials_to_dict(credentials: Credentials) -> Dict[str, Any]:
|
|
17
|
+
return {
|
|
18
|
+
"token": credentials.token,
|
|
19
|
+
"refresh_token": credentials.refresh_token,
|
|
20
|
+
"token_uri": credentials.token_uri,
|
|
21
|
+
"client_id": credentials.client_id,
|
|
22
|
+
"client_secret": credentials.client_secret,
|
|
23
|
+
"scopes": credentials.scopes,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def has_epoch_time_passed(target_epoch_time: Union[int, float]) -> bool:
|
|
28
|
+
"""
|
|
29
|
+
Checks if a given epoch time has passed.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
target_epoch_time (float or int): The epoch time to check (seconds since epoch).
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
bool: True if the target epoch time has passed, False otherwise.
|
|
36
|
+
"""
|
|
37
|
+
current_epoch_time = time.time()
|
|
38
|
+
return target_epoch_time <= current_epoch_time
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def check_gauth_authentication(session: Settings) -> Tuple[bool, object]:
|
|
42
|
+
"""
|
|
43
|
+
checks if authentication session still valid
|
|
44
|
+
"""
|
|
45
|
+
credentials_session_key = settings.CREDENTIALS_SESSION_KEY_NAME or "credentials"
|
|
46
|
+
|
|
47
|
+
if credentials_session_key not in session:
|
|
48
|
+
return False, None
|
|
49
|
+
|
|
50
|
+
# Load credentials from the session.
|
|
51
|
+
credentials = Credentials(**session[credentials_session_key])
|
|
52
|
+
|
|
53
|
+
if not credentials.valid:
|
|
54
|
+
return False, None
|
|
55
|
+
|
|
56
|
+
if "id_info" in session and has_epoch_time_passed(session["id_info"]["exp"]):
|
|
57
|
+
return False, None
|
|
58
|
+
|
|
59
|
+
return True, credentials
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def is_valid_google_url(url: str) -> bool:
|
|
63
|
+
VALID_SCHEME = "https" # pylint: disable=C0103
|
|
64
|
+
VALID_DOMAIN = "docs.google.com" # pylint: disable=C0103
|
|
65
|
+
try:
|
|
66
|
+
result = urlparse(url)
|
|
67
|
+
return (
|
|
68
|
+
all([result.scheme, result.netloc])
|
|
69
|
+
and result.scheme == VALID_SCHEME
|
|
70
|
+
and result.netloc == VALID_DOMAIN
|
|
71
|
+
)
|
|
72
|
+
except ValueError:
|
|
73
|
+
return False
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Auth Api's
|
|
3
|
+
~@ankit.kumar05
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from django.conf import settings # pylint: disable=E0401
|
|
7
|
+
from django.shortcuts import redirect, render # pylint: disable=E0401
|
|
8
|
+
from django.urls import reverse # pylint: disable=E0401
|
|
9
|
+
from google.auth.transport import requests # pylint: disable=E0401
|
|
10
|
+
from google.oauth2 import id_token # pylint: disable=E0401
|
|
11
|
+
from google_auth_oauthlib.flow import Flow # pylint: disable=E0401
|
|
12
|
+
|
|
13
|
+
from django_gauth import defaults
|
|
14
|
+
from django_gauth.utilities import check_gauth_authentication, credentials_to_dict
|
|
15
|
+
|
|
16
|
+
if hasattr(settings, "SCOPE") and settings.SCOPE:
|
|
17
|
+
SCOPE = settings.SCOPE
|
|
18
|
+
else:
|
|
19
|
+
SCOPE = []
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
hasattr(settings, "GOOGLE_AUTH_FINAL_REDIRECT_URL")
|
|
23
|
+
and settings.GOOGLE_AUTH_FINAL_REDIRECT_URL
|
|
24
|
+
):
|
|
25
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL = settings.GOOGLE_AUTH_FINAL_REDIRECT_URL
|
|
26
|
+
else:
|
|
27
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL = defaults.GOOGLE_AUTH_FINAL_REDIRECT_URL
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
hasattr(settings, "CREDENTIALS_SESSION_KEY_NAME")
|
|
31
|
+
and settings.CREDENTIALS_SESSION_KEY_NAME
|
|
32
|
+
):
|
|
33
|
+
CREDENTIALS_SESSION_KEY_NAME = settings.CREDENTIALS_SESSION_KEY_NAME
|
|
34
|
+
else:
|
|
35
|
+
CREDENTIALS_SESSION_KEY_NAME = defaults.CREDENTIALS_SESSION_KEY_NAME
|
|
36
|
+
|
|
37
|
+
if hasattr(settings, "STATE_KEY_NAME") and settings.STATE_KEY_NAME:
|
|
38
|
+
STATE_KEY_NAME = settings.STATE_KEY_NAME
|
|
39
|
+
else:
|
|
40
|
+
STATE_KEY_NAME = defaults.STATE_KEY_NAME
|
|
41
|
+
|
|
42
|
+
if hasattr(settings, "FINAL_REDIRECT_KEY_NAME") and settings.FINAL_REDIRECT_KEY_NAME:
|
|
43
|
+
FINAL_REDIRECT_KEY_NAME = settings.STATE_KEY_NAME
|
|
44
|
+
else:
|
|
45
|
+
FINAL_REDIRECT_KEY_NAME = defaults.FINAL_REDIRECT_KEY_NAME
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def index(request): # type: ignore
|
|
49
|
+
is_authenticated, _ = check_gauth_authentication(request.session)
|
|
50
|
+
id_info = request.session.get("id_info", {})
|
|
51
|
+
|
|
52
|
+
id_info.pop("iss", None)
|
|
53
|
+
id_info.pop("azp", None)
|
|
54
|
+
id_info.pop("aud", None)
|
|
55
|
+
id_info.pop("sub", None)
|
|
56
|
+
|
|
57
|
+
context: dict = {
|
|
58
|
+
"title": "",
|
|
59
|
+
"login_href": reverse("django_gauth:login"),
|
|
60
|
+
"user_info": id_info,
|
|
61
|
+
"is_authenticated": is_authenticated,
|
|
62
|
+
}
|
|
63
|
+
return render(request, "django_gauth/index.html", {"context_data": context})
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def login(request): # type: ignore
|
|
67
|
+
"""Login Api
|
|
68
|
+
- Initiates the oauth2 Flow
|
|
69
|
+
"""
|
|
70
|
+
flow = Flow.from_client_config(
|
|
71
|
+
client_config={
|
|
72
|
+
"web": {
|
|
73
|
+
"client_id": settings.GOOGLE_CLIENT_ID,
|
|
74
|
+
"client_secret": settings.GOOGLE_CLIENT_SECRET,
|
|
75
|
+
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
|
|
76
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
# if you need additional scopes, add them here
|
|
80
|
+
,
|
|
81
|
+
scopes=SCOPE,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# flow.redirect_uri = get_redirect_uri(request) # use this when
|
|
85
|
+
flow.redirect_uri = request.build_absolute_uri(reverse("django_gauth:callback"))
|
|
86
|
+
|
|
87
|
+
authorization_url, state = flow.authorization_url(
|
|
88
|
+
access_type="offline", prompt="select_account", include_granted_scopes="true"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
request.session[STATE_KEY_NAME] = state
|
|
92
|
+
if (
|
|
93
|
+
"final_redirect" not in request.session
|
|
94
|
+
or not request.session[FINAL_REDIRECT_KEY_NAME]
|
|
95
|
+
):
|
|
96
|
+
request.session[FINAL_REDIRECT_KEY_NAME] = (
|
|
97
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL
|
|
98
|
+
or request.build_absolute_uri(reverse("django_gauth:index"))
|
|
99
|
+
) # directs where to land after login is successful.
|
|
100
|
+
|
|
101
|
+
return redirect(authorization_url)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def callback(request): # type: ignore
|
|
105
|
+
"""Google Oauth2 Callback
|
|
106
|
+
- Google IDP response control transfer
|
|
107
|
+
"""
|
|
108
|
+
# pull the state from the session
|
|
109
|
+
session_state = request.session.get(STATE_KEY_NAME)
|
|
110
|
+
redirect_uri = request.build_absolute_uri(reverse("django_gauth:callback"))
|
|
111
|
+
authorization_response = request.build_absolute_uri()
|
|
112
|
+
# Flow Creation
|
|
113
|
+
flow = Flow.from_client_config(
|
|
114
|
+
client_config={
|
|
115
|
+
"web": {
|
|
116
|
+
"client_id": settings.GOOGLE_CLIENT_ID,
|
|
117
|
+
"client_secret": settings.GOOGLE_CLIENT_SECRET,
|
|
118
|
+
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
|
|
119
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
scopes=[
|
|
123
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
124
|
+
"https://www.googleapis.com/auth/userinfo.profile",
|
|
125
|
+
"openid",
|
|
126
|
+
"https://www.googleapis.com/auth/drive",
|
|
127
|
+
],
|
|
128
|
+
state=session_state,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
flow.redirect_uri = redirect_uri
|
|
132
|
+
# fetch token
|
|
133
|
+
flow.fetch_token(authorization_response=authorization_response)
|
|
134
|
+
# get credentials
|
|
135
|
+
credentials = flow.credentials
|
|
136
|
+
# verify token, while also retrieving information about the user
|
|
137
|
+
id_info = id_token.verify_oauth2_token(
|
|
138
|
+
id_token=credentials._id_token, # pylint: disable=W0212
|
|
139
|
+
request=requests.Request(),
|
|
140
|
+
audience=settings.GOOGLE_CLIENT_ID,
|
|
141
|
+
clock_skew_in_seconds=5,
|
|
142
|
+
)
|
|
143
|
+
# session setting
|
|
144
|
+
request.session["id_info"] = id_info
|
|
145
|
+
request.session[CREDENTIALS_SESSION_KEY_NAME] = credentials_to_dict(credentials)
|
|
146
|
+
# redirecting to the final redirect (i.e., logged in page)
|
|
147
|
+
redirect_response = redirect(request.session[FINAL_REDIRECT_KEY_NAME])
|
|
148
|
+
|
|
149
|
+
return redirect_response
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django_gauth
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: A Django app for providing the Google's discovery based Oauth2 authentication mechanism is HTTP/HTTPS oriented Django Servers/Projects.
|
|
5
|
+
Author-email: Ankit Kumar <ankit.kumar05@telusdigital.com>, Ankit Yadav <ankit8290@gmail.com>
|
|
6
|
+
Maintainer-email: Ankit yadav <ankit8290@gmail.com>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2025 Ankit Yadav
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Documentation, https://masterpiece93.github.io/django-gauth/
|
|
30
|
+
Project-URL: Repository, https://github.com/masterPiece93/django-gauth
|
|
31
|
+
Project-URL: Changelog, https://github.com/masterPiece93/django-gauth/releases
|
|
32
|
+
Keywords: django_gauth,google,oauth2,auth
|
|
33
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
34
|
+
Classifier: Environment :: Web Environment
|
|
35
|
+
Classifier: Framework :: Django
|
|
36
|
+
Classifier: Framework :: Django :: 3.1
|
|
37
|
+
Classifier: Intended Audience :: Developers
|
|
38
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
39
|
+
Classifier: Operating System :: OS Independent
|
|
40
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
45
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
46
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
47
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
48
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
49
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
50
|
+
Classifier: Topic :: Utilities
|
|
51
|
+
Classifier: Typing :: Typed
|
|
52
|
+
Requires-Python: >=3.9
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
License-File: LICENSE
|
|
55
|
+
Requires-Dist: Django>=3.1
|
|
56
|
+
Requires-Dist: google-api-python-client
|
|
57
|
+
Requires-Dist: google-auth-oauthlib
|
|
58
|
+
Requires-Dist: mypy>=1.18.1
|
|
59
|
+
Provides-Extra: dev
|
|
60
|
+
Requires-Dist: build==1.2.1; extra == "dev"
|
|
61
|
+
Requires-Dist: nox==2024.4.15; extra == "dev"
|
|
62
|
+
Requires-Dist: twine==5.1.1; extra == "dev"
|
|
63
|
+
Requires-Dist: check-wheel-contents; extra == "dev"
|
|
64
|
+
Requires-Dist: mypy; extra == "dev"
|
|
65
|
+
Requires-Dist: graphviz; extra == "dev"
|
|
66
|
+
Requires-Dist: pipdeptree; extra == "dev"
|
|
67
|
+
Provides-Extra: lint
|
|
68
|
+
Requires-Dist: codespell>=2.2.4; extra == "lint"
|
|
69
|
+
Requires-Dist: ruff; extra == "lint"
|
|
70
|
+
Requires-Dist: vulture; extra == "lint"
|
|
71
|
+
Requires-Dist: tomli; extra == "lint"
|
|
72
|
+
Requires-Dist: validate-pyproject[all]; extra == "lint"
|
|
73
|
+
Requires-Dist: isort; extra == "lint"
|
|
74
|
+
Requires-Dist: black; extra == "lint"
|
|
75
|
+
Requires-Dist: mypy; extra == "lint"
|
|
76
|
+
Requires-Dist: pylint; extra == "lint"
|
|
77
|
+
Requires-Dist: pylint-actions; extra == "lint"
|
|
78
|
+
Dynamic: license-file
|
|
79
|
+
|
|
80
|
+
# Google Auth <sup>[ Django ]<sup>
|
|
81
|
+
|
|
82
|
+
 [](https://github.com/masterPiece93/django-gauth/actions/workflows/pages/pages-build-deployment) [](https://github.com/masterPiece93/django-gauth/actions/workflows/pylint.yml)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
> [Official Documentation](https://masterpiece93.github.io/django-gauth/)
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
<!-- Implement Carousal -->
|
|
90
|
+
|
|
91
|
+
| Source | Command |
|
|
92
|
+
| ------ | ------- |
|
|
93
|
+
| **GitHub** | ```pip install -e git+https://github.com/masterPiece93/django-gauth.git#egg=django_gauth```|
|
|
94
|
+
| **PyPi**| ```pip install django-gauth``` |
|
|
95
|
+
|
|
96
|
+
## Quickstart
|
|
97
|
+
|
|
98
|
+
1. add the app name : `django_gauth` in **INSTALLED_APPS** entry of you project ( in settings.py file )
|
|
99
|
+
2. add required configuration variables ( in *settings.py* file )
|
|
100
|
+
```python
|
|
101
|
+
# settings.py
|
|
102
|
+
GOOGLE_CLIENT_ID= env("GOOGLE_CLIENT_ID") # << set according to your oauth2 client
|
|
103
|
+
GOOGLE_CLIENT_SECRET= env("GOOGLE_CLIENT_SECRET") # << set according to your oauth2 client
|
|
104
|
+
GOOGLE_AUTH_FINAL_REDIRECT_URL= None # defaults to `<host>/gauth/`
|
|
105
|
+
CREDENTIALS_SESSION_KEY_NAME= "credentials" # defaults to `credentials`
|
|
106
|
+
STATE_KEY_NAME= "oauth_state" # defaults to `oauth_state`
|
|
107
|
+
SCOPE= [
|
|
108
|
+
"https://www.googleapis.com/auth/userinfo.email" # always preffered
|
|
109
|
+
,"https://www.googleapis.com/auth/userinfo.profile" # always preffered
|
|
110
|
+
,"openid" # always preffered
|
|
111
|
+
,"https://www.googleapis.com/auth/drive" # based on your usage
|
|
112
|
+
]
|
|
113
|
+
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # strictly for local-development only
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- `os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'` directs the server to accept in-secure (http) connections .
|
|
117
|
+
|
|
118
|
+
3. configure auth urls ( in *urls.py* file of root )
|
|
119
|
+
```python
|
|
120
|
+
# urls.py
|
|
121
|
+
from django.contrib import admin
|
|
122
|
+
from django.urls import path, include
|
|
123
|
+
|
|
124
|
+
urlpatterns = [
|
|
125
|
+
path('admin/', admin.site.urls),
|
|
126
|
+
path('gauth/', include('django_gauth.urls')),
|
|
127
|
+
|
|
128
|
+
# add your other app's urls
|
|
129
|
+
# ...
|
|
130
|
+
|
|
131
|
+
]
|
|
132
|
+
```
|
|
133
|
+
* NOTE :
|
|
134
|
+
useually all servers ( **wsgi**, **asgi**, **uWsgi**) runs default on `http://127.0.0.1:PORT/` , hence always take care to set the redirect endpoints in your google oauth2 client app in accordance with *127.0.0.1* , don't mistake to consider *localhost* , *0.0.0.0* and *127.0.0.1* as the same thing while dealing with redirect uri's .
|
|
135
|
+
- For example : suppose you have set `http://localhost:PORT/gauth/google-callback` as your redirect uri , then take note of running your django app on localhost:PORT only !!
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
<br>
|
|
139
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pypi.README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
src/django_gauth/__init__.py
|
|
6
|
+
src/django_gauth/admin.py
|
|
7
|
+
src/django_gauth/apps.py
|
|
8
|
+
src/django_gauth/defaults.py
|
|
9
|
+
src/django_gauth/py.typed
|
|
10
|
+
src/django_gauth/urls.py
|
|
11
|
+
src/django_gauth/utilities.py
|
|
12
|
+
src/django_gauth/views.py
|
|
13
|
+
src/django_gauth.egg-info/PKG-INFO
|
|
14
|
+
src/django_gauth.egg-info/SOURCES.txt
|
|
15
|
+
src/django_gauth.egg-info/dependency_links.txt
|
|
16
|
+
src/django_gauth.egg-info/requires.txt
|
|
17
|
+
src/django_gauth.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Django>=3.1
|
|
2
|
+
google-api-python-client
|
|
3
|
+
google-auth-oauthlib
|
|
4
|
+
mypy>=1.18.1
|
|
5
|
+
|
|
6
|
+
[dev]
|
|
7
|
+
build==1.2.1
|
|
8
|
+
nox==2024.4.15
|
|
9
|
+
twine==5.1.1
|
|
10
|
+
check-wheel-contents
|
|
11
|
+
mypy
|
|
12
|
+
graphviz
|
|
13
|
+
pipdeptree
|
|
14
|
+
|
|
15
|
+
[lint]
|
|
16
|
+
codespell>=2.2.4
|
|
17
|
+
ruff
|
|
18
|
+
vulture
|
|
19
|
+
tomli
|
|
20
|
+
validate-pyproject[all]
|
|
21
|
+
isort
|
|
22
|
+
black
|
|
23
|
+
mypy
|
|
24
|
+
pylint
|
|
25
|
+
pylint-actions
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
django_gauth
|