import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import Cookies from 'js-cookie'; // Import js-cookie
const GoogleCallback = () => {
const navigate = useNavigate();
useEffect(() => {
const handleCallback = async () => {
try {
await axios.get(
"http://localhost:8000/api/google/callback/" + window.location.search,
{ withCredentials: true } // Ensure cookies are sent & received
);
// Check for both tokens using js-cookie with domain and path
const accessToken = Cookies.get('access_token', { domain: '127.0.0.1', path: '/' });
const refreshToken = Cookies.get('refresh_token', { domain: '127.0.0.1', path: '/' });
if (accessToken && refreshToken) {
navigate("/");
} else {
console.warn("Access token or refresh token not found in cookies under 127.0.0.1:5173");
navigate("/login");
}
} catch (error) {
console.error("Google login failed", error);
navigate("/login");
}
};
handleCallback();
}, [navigate]);
return Logging in...;
};
export default GoogleCallback;
< /code>
from django.shortcuts import redirect
from django.http import JsonResponse
import requests
from django.conf import settings
from django.contrib.auth import get_user_model
from allauth.socialaccount.models import SocialAccount, SocialToken
from rest_framework_simplejwt.tokens import RefreshToken
from datetime import timedelta
from django.utils.timezone import now
from django.core.exceptions import ObjectDoesNotExist
User = get_user_model()
def google_login(request):
"""Redirects the user to Google's OAuth 2.0 authentication page."""
google_oauth_url = (
"https://accounts.google.com/o/oauth2/auth"
"?response_type=code"
f"&client_id={settings.SOCIAL_AUTH_GOOGLE_CLIENT_ID}"
f"&redirect_uri={settings.SOCIAL_AUTH_GOOGLE_REDIRECT_URI}"
"&scope=email%20profile%20openid"
"&access_type=offline"
"&prompt=consent"
)
return redirect(google_oauth_url)
def google_login_callback(request):
"""Handles OAuth callback, exchanges code for Google tokens, and generates JWTs."""
code = request.GET.get('code')
if not code:
return JsonResponse({'error': 'Missing authorization code'}, status=400)
# Exchange code for access & refresh tokens
token_url = "https://oauth2.googleapis.com/token"
data = {
'code': code,
'client_id': settings.SOCIAL_AUTH_GOOGLE_CLIENT_ID,
'client_secret': settings.SOCIAL_AUTH_GOOGLE_SECRET,
'redirect_uri': settings.SOCIAL_AUTH_GOOGLE_REDIRECT_URI,
'grant_type': 'authorization_code',
}
response = requests.post(token_url, data=data)
token_data = response.json()
if 'error' in token_data:
return JsonResponse({'error': 'Failed to fetch tokens', 'details': token_data}, status=400)
access_token = token_data.get('access_token')
refresh_token = token_data.get('refresh_token')
id_token = token_data.get('id_token')
# Fetch user info from Google
user_info_url = "https://www.googleapis.com/oauth2/v2/userinfo"
headers = {'Authorization': f'Bearer {access_token}'}
user_info_response = requests.get(user_info_url, headers=headers)
user_info = user_info_response.json()
if 'email' not in user_info:
return JsonResponse({'error': 'Google authentication failed'}, status=400)
email = user_info['email']
# Check if user exists, create if not
user, created = User.objects.get_or_create(username=email, defaults={'email': email})
# Store Google tokens in SocialToken model
try:
social_account = SocialAccount.objects.get(user=user, provider='google')
except ObjectDoesNotExist:
social_account = SocialAccount.objects.create(user=user, provider='google', extra_data=user_info)
social_token, _ = SocialToken.objects.update_or_create(
account=social_account,
defaults={'token': access_token, 'token_secret': refresh_token, 'expires_at': now() + timedelta(seconds=token_data.get("expires_in", 3600))}
)
# Generate JWT tokens
refresh = RefreshToken.for_user(user)
access = refresh.access_token
# Set JWT tokens as secure HTTP-only cookies
response = JsonResponse({'message': 'Login successful'})
response.set_cookie('access_token', str(access), httponly=True, secure=True, samesite='Lax')
response.set_cookie('refresh_token', str(refresh), httponly=True, secure=True, samesite='Lax')
return response
def refresh_google_token(user):
"""Refreshes the user's Google OAuth token if expired."""
try:
social_account = SocialAccount.objects.get(user=user, provider='google')
social_token = SocialToken.objects.get(account=social_account)
if social_token.expires_at and social_token.expires_at < now():
token_url = "https://oauth2.googleapis.com/token"
data = {
'client_id': settings.SOCIAL_AUTH_GOOGLE_CLIENT_ID,
'client_secret': settings.SOCIAL_AUTH_GOOGLE_SECRET,
'refresh_token': social_token.token_secret,
'grant_type': 'refresh_token',
}
response = requests.post(token_url, data=data)
new_token_data = response.json()
if 'access_token' in new_token_data:
social_token.token = new_token_data['access_token']
social_token.expires_at = now() + timedelta(seconds=new_token_data.get("expires_in", 3600))
social_token.save()
return new_token_data['access_token']
else:
return None
return social_token.token
except ObjectDoesNotExist:
return None
from rest_framework_simplejwt.tokens import AccessToken
def verify_user(request):
"""Verifies the user's authentication using JWT stored in cookies."""
access_token = request.COOKIES.get("access_token")
if not access_token:
return JsonResponse({'authenticated': False, 'error': 'No access token'}, status=401)
try:
payload = AccessToken(access_token)
user = User.objects.get(id=payload['user_id'])
return JsonResponse({'authenticated': True, 'email': user.email})
except Exception:
return JsonResponse({'authenticated': False, 'error': 'Invalid or expired token'}, status=401)
< /code>
import { useEffect, useState } from "react";
import { verifyUser, refreshGoogleToken } from "./api";
import { useNavigate } from "react-router-dom";
const Home = () => {
const [user, setUser] = useState(null);
const navigate = useNavigate();
useEffect(() => {
const checkUser = async () => {
const data = await verifyUser();
if (data.authenticated) {
setUser(data);
} else {
console.warn("User verification failed:", data.error);
navigate("/login"); // Redirect immediately if not authenticated - Removed setTimeout delay
}
};
checkUser();
}, [navigate]);
return (
{user ? (
Welcome, {user.email}
) : (
Loading...
)}
);
};
export default Home;
< /code>

Подробнее здесь: https://stackoverflow.com/questions/794 ... ogle-login
Мобильная версия