Skip to content

Commit 5bdf3b1

Browse files
committed
google auth
1 parent 5df3929 commit 5bdf3b1

7 files changed

Lines changed: 177 additions & 4 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Generated by Django 6.1 on 2026-08-23 16:39
2+
3+
import uuid
4+
5+
import django.db.models.deletion
6+
from django.conf import settings
7+
from django.db import migrations, models
8+
9+
10+
class Migration(migrations.Migration):
11+
initial = True
12+
13+
dependencies = [
14+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15+
]
16+
17+
operations = [
18+
migrations.CreateModel(
19+
name="UserProfile",
20+
fields=[
21+
(
22+
"id",
23+
models.UUIDField(
24+
default=uuid.uuid4,
25+
editable=False,
26+
primary_key=True,
27+
serialize=False,
28+
),
29+
),
30+
(
31+
"user",
32+
models.OneToOneField(
33+
on_delete=django.db.models.deletion.CASCADE,
34+
related_name="profile",
35+
to=settings.AUTH_USER_MODEL,
36+
),
37+
),
38+
],
39+
),
40+
]

‎backend/apps/authentication/urls.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@
55
urlpatterns = [
66
path("register/", views.RegisterationView.as_view(), name="register"),
77
path("login/", views.LoginView.as_view(), name="login"),
8+
path("<str:provider>/", views.OAuthLoginView.as_view()),
9+
path("<str:provider>/callback/", views.OAuthCallbackView.as_view()),
10+
# path("google/",views.GoogleLogin.as_view(),name="google_login"),
811
]

‎backend/apps/authentication/views.py‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
from urllib.parse import urlencode
2+
3+
import requests
4+
from django.conf import settings
15
from django.contrib.auth.models import User
6+
from django.shortcuts import redirect
27
from rest_framework import generics, status
8+
from rest_framework.permissions import AllowAny
39
from rest_framework.response import Response
10+
from rest_framework.views import APIView
411
from rest_framework_simplejwt.tokens import RefreshToken
512

613
from .models import UserProfile
@@ -62,3 +69,59 @@ def create(self, request, *args, **kwags):
6269
},
6370
status=status.HTTP_200_OK,
6471
)
72+
73+
74+
"""
75+
class GoogleLogin(SocialLoginView):
76+
adapter_class = GoogleOAuth2Adapter
77+
client_class = OAuth2Client
78+
callback_url = "http://127.0.0.1:8000/accounts/google/login/callback/"
79+
"""
80+
81+
82+
class OAuthLoginView(APIView):
83+
permission_classes = [AllowAny]
84+
85+
def get(self, request, provider):
86+
if provider != "google":
87+
return Response({"error": "Unsupported provider"}, status=400)
88+
params = {
89+
"client_id": settings.GOOGLE_CLIENT_ID,
90+
"redirect_uri": settings.GOOGLE_REDIRECT_URI,
91+
"response_type": "code",
92+
"scope": "openid email profile",
93+
"access_type": "offline",
94+
}
95+
google_url = "https://accounts.google.com/o/oauth2/v2/auth?" + urlencode(params)
96+
return redirect(google_url)
97+
98+
99+
class OAuthCallbackView(APIView):
100+
permission_classes = [AllowAny]
101+
102+
def get(self, request, provider):
103+
if provider != "google":
104+
return Response({"error": "Unsupported provider"}, status=400)
105+
code = request.GET.get("code")
106+
if not code:
107+
return Response({"error": "Authorization code missing"}, status=400)
108+
token_response = requests.post(
109+
"https://oauth2.googleapis.com/token",
110+
data={
111+
"code": code,
112+
"client_id": settings.GOOGLE_CLIENT_ID,
113+
"client_secret": settings.GOOGLE_CLIENT_SECRET,
114+
"redirect_uri": settings.GOOGLE_REDIRECT_URI,
115+
"grant_type": "authorization_code",
116+
},
117+
)
118+
token_data = token_response.json()
119+
access_token = token_data.get("access_token")
120+
if not access_token:
121+
return Response({"error": "Failed to get access_token"}, status=400)
122+
user_response = requests.get(
123+
"https://www.googleapis.com/oauth2/v2/userinfo",
124+
headers={"Authorization": f"Bearer {access_token}"},
125+
)
126+
user_data = user_response.json()
127+
return Response(user_data)

‎backend/config/settings/base.py‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import os
22
from pathlib import Path
33

4+
from dotenv import load_dotenv
5+
6+
load_dotenv()
7+
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
8+
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
9+
GOOGLE_REDIRECT_URI = os.getenv("GOOGLE_REDIRECT_URI")
410
# BASE_DIR points to the root of your backend project (/app)
511
BASE_DIR = Path(__file__).resolve().parent.parent.parent
612

@@ -12,11 +18,20 @@
1218
"django.contrib.sessions",
1319
"django.contrib.messages",
1420
"django.contrib.staticfiles",
21+
"rest_framework.authtoken",
1522
# Third-party apps
1623
"rest_framework",
1724
"rest_framework_simplejwt",
1825
# Local apps
1926
"apps.authentication",
27+
# dj_auth_apps
28+
"dj_rest_auth",
29+
"dj_rest_auth.registration",
30+
# allauth
31+
"allauth",
32+
"allauth.account",
33+
"allauth.socialaccount",
34+
"allauth.socialaccount.providers.google",
2035
]
2136

2237
MIDDLEWARE = [
@@ -27,6 +42,7 @@
2742
"django.contrib.auth.middleware.AuthenticationMiddleware",
2843
"django.contrib.messages.middleware.MessageMiddleware",
2944
"django.middleware.clickjacking.XFrameOptionsMiddleware",
45+
"allauth.account.middleware.AccountMiddleware",
3046
]
3147

3248
ROOT_URLCONF = "config.urls"
@@ -90,3 +106,27 @@
90106

91107
# Default primary key field type
92108
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
109+
SITE_ID = 1
110+
AUTHENTICATION_BACKENDS = [
111+
"django.contrib.auth.backends.ModelBackend",
112+
"allauth.account.auth_backends.AuthenticationBackend",
113+
]
114+
REST_FRAMEWORK = {
115+
"DEFAULT_AUTHENTICATION_CLASSES": [
116+
"rest_framework.authentication.TokenAuthentication",
117+
],
118+
}
119+
120+
SOCIALACCOUNT_PROVIDERS = {
121+
"google": {
122+
"SCOPE": [
123+
"profile",
124+
"email",
125+
],
126+
"AUTH_PARAMS": {
127+
"access_type": "online",
128+
},
129+
},
130+
}
131+
132+
LOGIN_REDIRECT_URL = "/"

‎backend/config/urls.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
urlpatterns = [
2222
path("admin/", admin.site.urls),
2323
path("api/auth/", include("apps.authentication.urls")),
24+
# path("accounts/", include("allauth.urls")),
2425
# path("catalog/", include("apps.catalog.urls")),
2526
# path("order/", include("apps.orders.urls")),
2627
# path("profile/", include("apps.profiles.urls")),

‎backend/pyproject.toml‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@ dependencies = [
1313
"djangorestframework>=3.15.0",
1414
"djangorestframework-simplejwt>=5.3.1",
1515
"django-cors-headers>=4.4.0",
16-
1716
# Database
1817
"psycopg[binary]>=3.2.0",
19-
2018
# Production WSGI Server
2119
"gunicorn>=23.0.0",
22-
2320
# Utilities & OAuth Integrations
2421
"python-dotenv>=1.0.1",
2522
"requests>=2.32.0",
23+
"dj-rest-auth>=7.2.0",
24+
"django-allauth>=65.19.1",
2625
]
2726

2827
[tool.uv]
@@ -51,4 +50,4 @@ select = [
5150
[tool.pytest.ini_options]
5251
DJANGO_SETTINGS_MODULE = "config.settings.local"
5352
python_files = ["test_*.py", "*_test.py", "tests.py"]
54-
addopts = "--strict-markers --no-migrations"
53+
addopts = "--strict-markers --no-migrations"

‎backend/uv.lock‎

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)