This content originally appeared on DEV Community and was authored by cycy
Integrating Google OAuth2 authentication in a Django REST API can be tricky, especially with changing library APIs and the need to support both web and mobile clients. Here’s a practical, robust approach that avoids common pitfalls and works reliably with modern Django and Google APIs.
1. Why Not Use Allauth Adapters Directly?
While django-allauth
is a popular library for social authentication, its internal APIs (like get_app
and direct use of adapters) can change or become unstable. Relying on these can lead to hard-to-debug errors, especially after library upgrades.
Solution:
Use the official Google OAuth2 HTTP endpoints directly for the callback, and only use allauth for registration flows if you need them.
2. The OAuth2 Flow Overview
- User clicks “Sign in with Google” on your frontend.
- Frontend redirects user to Google’s OAuth2 consent screen.
-
Google redirects back to your backend callback with a
code
parameter. - Backend exchanges the code for tokens using Google’s token endpoint.
- Backend fetches user info from Google using the access token.
- Backend creates or retrieves the user in your database.
- Backend generates JWT tokens for your frontend.
- Backend redirects the user to the frontend dashboard with tokens.
3. Backend Implementation Steps
a. Environment Variables
Set these in your .env file:
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_CALLBACK_URL=http://localhost:8002/api/users/auth/google/callback/
FRONTEND_URL=http://localhost:3001
b. Django Settings
Add or update in settings.py:
SOCIALACCOUNT_PROVIDERS = {
"google": {
"APP": {
"client_id": os.environ.get("GOOGLE_CLIENT_ID"),
"secret": os.environ.get("GOOGLE_CLIENT_SECRET"),
"key": "",
},
"SCOPE": [
"profile",
"email",
],
"AUTH_PARAMS": {
"access_type": "online",
},
}
}
GOOGLE_CALLBACK_URL = os.environ.get("GOOGLE_CALLBACK_URL")
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
FRONTEND_URL = os.environ.get("FRONTEND_URL")
c. OAuth2 Callback View
Instead of using allauth’s adapter methods, use direct HTTP requests:
# views.py or google_auth_views.py
import requests
from django.conf import settings
from django.core.exceptions import ValidationError
from django.shortcuts import redirect
from rest_framework.views import APIView
class GoogleOAuthCallbackView(APIView):
def get(self, request, *args, **kwargs):
code = request.GET.get("code")
if not code:
return redirect(f"{settings.FRONTEND_URL}/login?error=oauth_no_code")
try:
# Exchange code for tokens
token_url = "https://oauth2.googleapis.com/token"
token_data = {
'client_id': settings.GOOGLE_CLIENT_ID,
'client_secret': settings.GOOGLE_CLIENT_SECRET,
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': settings.GOOGLE_CALLBACK_URL,
}
token_response = requests.post(token_url, data=token_data)
token_response.raise_for_status()
token_info = token_response.json()
# Get user info
user_info_url = f"https://www.googleapis.com/oauth2/v2/userinfo?access_token={token_info['access_token']}"
user_response = requests.get(user_info_url)
user_response.raise_for_status()
user_data = user_response.json()
email = user_data.get('email')
if not email:
raise ValidationError("Email not provided by Google")
# Create or get user (pseudo-code, adapt to your User model)
user, created = User.objects.get_or_create(
email=email,
defaults={
'first_name': user_data.get('given_name', ''),
'last_name': user_data.get('family_name', ''),
}
)
# Create user profile if needed (pseudo-code)
create_user_profile(user, user_type="sender") # or "rider"
# Generate JWT tokens (using SimpleJWT)
from rest_framework_simplejwt.tokens import RefreshToken
refresh = RefreshToken.for_user(user)
tokens = {
"access": str(refresh.access_token),
"refresh": str(refresh)
}
# Redirect to frontend dashboard with tokens as query params
dashboard_url = f"{settings.FRONTEND_URL}/dashboard"
redirect_url = f"{dashboard_url}?access_token={tokens['access']}&refresh_token={tokens['refresh']}"
return redirect(redirect_url)
except Exception as e:
return redirect(f"{settings.FRONTEND_URL}/login?error=auth_failed")
4. Frontend Handling
- After redirect, the frontend should read the tokens from the URL and store them (e.g., in localStorage or cookies).
- Use these tokens for authenticated API requests.
5. Common Pitfalls & Lessons Learned
- Don’t rely on allauth’s internal adapter methods for the callback—they may change or break.
- Always use the official Google OAuth2 endpoints for exchanging codes and fetching user info.
- Keep your callback URL and Google Cloud Console settings in sync (including port numbers).
- Handle errors gracefully and always redirect to a safe frontend route with an error message if something fails.
- Deprecation warnings from dj-rest-auth/allauth are safe to ignore if you use the new config style.
6. Conclusion
This approach is robust, simple, and easy to maintain.
If you ever upgrade Django, allauth, or dj-rest-auth, you won’t be caught off guard by breaking API changes in their internals.
Just use the official OAuth2 endpoints and keep your user creation/profile logic in your own code.
Bookmark this guide for future projects!
It will save you hours of debugging and frustration.
This content originally appeared on DEV Community and was authored by cycy

cycy | Sciencx (2025-06-16T14:29:36+00:00) How to Set Up Google OAuth2 Authentication in a Django REST API. Retrieved from https://www.scien.cx/2025/06/16/how-to-set-up-google-oauth2-authentication-in-a-django-rest-api/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.