from django.shortcuts import redirect from django.views import View from rest_framework import status from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import AllowAny from rest_framework_simplejwt.tokens import RefreshToken from social_django.utils import load_strategy, load_backend from social_core.backends.oauth import BaseOAuth2 from social_core.exceptions import AuthException, AuthForbidden from .serializers import SocialLoginSerializer, CustomUserSerializer import json class SocialLoginView(APIView): """ Social authentication endpoint. Accepts access_token from social provider and returns JWT tokens. POST /api/v1/auth/social// Body: { "access_token": "..." } Supported providers: google-oauth2, github, facebook """ permission_classes = [AllowAny] serializer_class = SocialLoginSerializer def post(self, request, provider): """ Authenticate user with social provider token. """ # Validate provider valid_providers = ['google-oauth2', 'github', 'facebook'] if provider not in valid_providers: return Response( {'error': f'Invalid provider. Must be one of: {", ".join(valid_providers)}'}, status=status.HTTP_400_BAD_REQUEST ) # Get access_token from request access_token = request.data.get('access_token') id_token = request.data.get('id_token', None) if not access_token: return Response( {'error': 'access_token is required'}, status=status.HTTP_400_BAD_REQUEST ) try: # Load social auth strategy and backend strategy = load_strategy(request) backend = load_backend( strategy=strategy, name=provider, redirect_uri=None ) # Verify token and get user if isinstance(backend, BaseOAuth2): # For OAuth2 providers, use access_token to get user info user = backend.do_auth(access_token) else: return Response( {'error': 'Unsupported authentication backend'}, status=status.HTTP_400_BAD_REQUEST ) if not user: return Response( {'error': 'Authentication failed. Invalid token.'}, status=status.HTTP_401_UNAUTHORIZED ) # Check if user is active if not user.is_active: # This shouldn't happen for social auth users, but just in case user.is_active = True user.save(update_fields=['is_active']) # Generate JWT tokens refresh = RefreshToken.for_user(user) # Serialize user data user_serializer = CustomUserSerializer(user) return Response({ 'access': str(refresh.access_token), 'refresh': str(refresh), 'user': user_serializer.data }, status=status.HTTP_200_OK) except AuthForbidden: return Response( {'error': 'Authentication forbidden. Email not provided by provider or permission denied.'}, status=status.HTTP_403_FORBIDDEN ) except AuthException as e: return Response( {'error': f'Authentication error: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST ) except Exception as e: return Response( {'error': f'An error occurred during authentication: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR ) class SocialAuthCallbackView(View): """ Callback view for OAuth flow completion. After successful authentication, redirects to frontend with tokens. """ permission_classes = [AllowAny] authentication_classes = [] # No authentication required for callback def get(self, request): """Handle OAuth callback and redirect to frontend with JWT tokens.""" from django.http import HttpResponseRedirect # Get the authenticated user from the session user = request.user if user and user.is_authenticated: # Generate JWT tokens refresh = RefreshToken.for_user(user) # Redirect to SPA with tokens (for testing) redirect_url = f"/api/v1/spa/?access={str(refresh.access_token)}&refresh={str(refresh)}" print(f"[OAuth Callback] Redirecting to: {redirect_url}") return HttpResponseRedirect(redirect_url) else: # Authentication failed return HttpResponseRedirect("/api/v1/auth/social/error/?error=authentication_failed") class SocialAuthSuccessView(APIView): """ Success page after social authentication. Displays tokens for testing purposes. """ permission_classes = [AllowAny] authentication_classes = [] # No authentication required def get(self, request): """Display success page with tokens.""" access_token = request.GET.get('access', '') refresh_token = request.GET.get('refresh', '') # Also check if user is in session if not access_token and request.user.is_authenticated: refresh = RefreshToken.for_user(request.user) access_token = str(refresh.access_token) refresh_token = str(refresh) html_content = f""" Authentication Successful

Authentication Successful!

You have successfully authenticated with your social account.

Access Token:
{access_token}
Refresh Token:
{refresh_token}
""" from django.http import HttpResponse return HttpResponse(html_content)