Django Googler is a simple way to integrate Google Auth Platform with your Django project.
Project description
Django Googler
Django Googler is a simple way to integrate Google OAuth Platform with your Django project. It provides both Django Rest Framework API views and regular Django views for handling Google OAuth authentication flows.
Features
- 🔐 Google OAuth 2.0 Integration - Complete OAuth flow implementation
- 🎯 Dual View Support - Both DRF API views and regular Django views
- 🔧 Service Layer Architecture - Clean separation of business logic
- ⚙️ Highly Configurable - Override settings via Django settings
- 🛡️ CSRF Protection - Built-in state verification
- 👥 Automatic User Management - Create or update users from Google info
- 💾 Database Token Storage - Persistent OAuth token storage with auto-refresh
- 🔄 Token Management - Automatic token refresh when expired
- 🎛️ Django Admin Integration - Manage OAuth tokens via Django admin
- 📦 Zero Configuration - Works out of the box with sensible defaults
- 🚦 Rate Limiting - Built-in throttling to prevent abuse
- ✅ Settings Validation - Django system checks for configuration
- 📝 DRF Serializers - Proper request/response validation
Installation
pip install django-googler
Dependencies
Quick Start
1. Add to Installed Apps
# settings.py
INSTALLED_APPS = [
# ...
"rest_framework",
"rest_framework.authtoken", # Required for API token authentication
"django_googler",
]
2. Configure Google OAuth Settings
Get your credentials from Google Cloud Console:
# settings.py
import os
# Required: Get these from Google Cloud Console
GOOGLE_OAUTH_CLIENT_ID = os.environ.get("GOOGLE_OAUTH_CLIENT_ID")
GOOGLE_OAUTH_CLIENT_SECRET = os.environ.get("GOOGLE_OAUTH_CLIENT_SECRET")
# Optional: Override default redirect URIs
GOOGLE_OAUTH_REDIRECT_URIS = [
"http://localhost:8000/auth/google/callback/",
"http://localhost:8000/api/auth/google/callback/",
]
# Optional: Override default scopes
GOOGLE_OAUTH_SCOPES = [
"openid",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
]
# Optional: Save OAuth tokens to database (recommended for persistent storage)
# Default: True
GOOGLE_OAUTH_SAVE_TOKENS_TO_DB = True
# Optional: Store OAuth tokens in session (legacy, use database storage instead)
# Default: False
GOOGLE_OAUTH_STORE_TOKENS = False
# Optional: Return Google tokens in API callback response (for frontend Google API calls)
# Default: False (only returns DRF token)
GOOGLE_OAUTH_RETURN_TOKENS = False
# Optional: Revoke Google OAuth tokens on logout
# Default: False
GOOGLE_OAUTH_REVOKE_ON_LOGOUT = False
# Optional: Login URL for error redirects
# Default: "/login/"
LOGIN_URL = "/admin/login/"
3. Run Migrations
python manage.py migrate
This creates the necessary database tables for:
- DRF authentication tokens (
authtoken) - Google OAuth token storage (
django_googler)
4. Add URL Patterns
Choose between Regular Django Views or Django Rest Framework API Views (or use both!):
Regular Django Views
# urls.py
from django.urls import path, include
urlpatterns = [
path("auth/", include("django_googler.urls.default")),
]
Or explicitly:
# urls.py
from django.urls import path
from django_googler import GoogleOAuthLoginView, GoogleOAuthCallbackView
urlpatterns = [
path("auth/google/login/", GoogleOAuthLoginView.as_view(), name="google-login"),
path(
"auth/google/callback/",
GoogleOAuthCallbackView.as_view(),
name="google-callback",
),
]
Django Rest Framework API Views
# urls.py
from django.urls import path, include
urlpatterns = [
path("api/auth/", include("django_googler.urls.drf")),
]
Or explicitly:
# urls.py
from django.urls import path
from django_googler import (
GoogleOAuthLoginAPIView,
GoogleOAuthCallbackAPIView,
CurrentUserAPIView,
GoogleOAuthLogoutAPIView,
)
urlpatterns = [
path(
"api/auth/google/login/",
GoogleOAuthLoginAPIView.as_view(),
name="google-login-api",
),
path(
"api/auth/google/callback/",
GoogleOAuthCallbackAPIView.as_view(),
name="google-callback-api",
),
path("api/auth/me/", CurrentUserAPIView.as_view(), name="current-user"),
path("api/auth/logout/", GoogleOAuthLogoutAPIView.as_view(), name="logout"),
]
Usage
Regular Django Views (Browser Redirects)
-
Redirect users to the login view:
<a href="{% url 'django_googler:google-login' %}?next=/dashboard/">Sign in with Google</a>
-
Users are redirected to Google for authentication
-
After authentication, users are redirected back and automatically logged in
The regular Django views will:
- Create a new user if they don't exist
- Update existing user information
- Log the user into Django's authentication system
- Redirect to the
nextparameter or/by default
Django Rest Framework API Views (JSON Responses)
-
GET the login endpoint to get the authorization URL:
curl http://localhost:8000/api/auth/google/login/Response:
{ "authorization_url": "https://accounts.google.com/o/oauth2/auth?...", "state": "random-state-string" }
-
Redirect users to the
authorization_url -
After Google redirects back with the authorization code, POST it to the callback:
curl -X POST http://localhost:8000/api/auth/google/callback/ \ -H "Content-Type: application/json" \ -d '{ "code": "4/0AY0e-g...", "state": "random-state-string", "redirect_uri": "http://localhost:3000/auth/callback" }'
Response (user is created/logged in and API token returned):
{ "token": "drf_api_token_abc123...", "user": { "id": 1, "email": "user@example.com", "username": "user", "first_name": "John", "last_name": "Doe" } }
Note: Google tokens are not included by default. If your frontend needs to call Google APIs directly (Calendar, Drive, Gmail, etc.), set
GOOGLE_OAUTH_RETURN_TOKENS = Truein settings to include them in the response. -
Use the returned token for authenticated requests:
curl http://localhost:8000/api/protected/ \ -H "Authorization: Token drf_api_token_abc123..."
Additional DRF Endpoints
Get Current User
curl http://localhost:8000/api/auth/me/ \
-H "Authorization: Token your-token-here"
Response:
{
"id": 1,
"email": "user@example.com",
"username": "user",
"first_name": "John",
"last_name": "Doe"
}
Logout
curl -X POST http://localhost:8000/api/auth/logout/ \
-H "Authorization: Token your-token-here"
Response:
{
"message": "Logged out successfully"
}
This will:
- Delete the user's DRF authentication token
- Clear all OAuth session data (access tokens, refresh tokens, etc.)
Advanced Usage
Using the Service Layer
You can use the service layer directly in your own views or logic:
from django_googler import GoogleOAuthService, UserService, OAuthFlowService
# Verify and process OAuth credentials
credentials_data = GoogleOAuthService.process_credentials(credentials)
# Create or update user from OAuth info
user, _ = UserService.get_or_create_user(
email="user@example.com",
name="John Doe",
google_id="1234567890",
picture="https://...",
)
# Manage OAuth flow state
OAuthFlowService.store_state(request, state)
is_valid = OAuthFlowService.verify_state(request, state)
OAuthFlowService.clear_state(request)
Custom Scopes
Request additional Google API scopes:
<!-- In your template -->
<a href="{% url 'django_googler:google-login' %}?scopes=openid,email,profile,https://www.googleapis.com/auth/calendar">
Sign in with Google Calendar Access
</a>
Or for API views:
curl "http://localhost:8000/api/auth/google/login/?scopes=openid,email,profile"
Database Token Storage (Recommended)
New in v0.0.4: OAuth tokens are now automatically saved to the database by default. This allows your backend to make Google API calls on behalf of users and automatically refresh expired tokens.
Accessing Stored Tokens
from django_googler.services import GoogleOAuthService
# Get user's token
def my_view(request):
# Option 1: Get valid token (auto-refreshes if expired)
access_token, expiry = GoogleOAuthService.get_valid_token(request.user)
if access_token:
# Use token to call Google APIs
import requests
headers = {"Authorization": f"Bearer {access_token}"}
response = requests.get(
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
headers=headers,
)
events = response.json()
# Option 2: Get token object directly
token = GoogleOAuthService.get_user_token(request.user)
if token:
if token.is_expired():
# Manually refresh if needed
token = GoogleOAuthService.refresh_user_token(token)
# Check scopes
if token.has_scope("https://www.googleapis.com/auth/calendar"):
# User has calendar access
pass
Token Model
The GoogleOAuthToken model stores:
- Access token (for API calls)
- Refresh token (for getting new access tokens)
- Token expiry datetime
- OAuth scopes granted
- Google ID (sub claim)
- ID token (JWT)
from django_googler.models import GoogleOAuthToken
# Get user's token
token = GoogleOAuthToken.objects.get(user=request.user)
# Check status
if token.is_valid:
print("Token is valid and not expired")
if token.can_refresh:
print("Token can be refreshed")
# Get scopes
scopes = token.get_scopes_list()
# ['openid', 'email', 'profile']
Django Admin
View and manage OAuth tokens in Django admin at /admin/django_googler/googleoauthtoken/:
- See token status (Valid/Expired/Invalid)
- View granted scopes
- Search by user email or Google ID
- Filter by date or expiry
- Delete tokens when needed
Token Management
from django_googler.services import GoogleOAuthService
# Save/update a user's token (automatically called during OAuth flow)
token = GoogleOAuthService.save_user_token(
user=request.user,
credentials=credentials,
google_id="1234567890",
scopes=["email", "profile"],
)
# Refresh an expired token
token = GoogleOAuthService.refresh_user_token(request.user)
# Revoke and delete a token
GoogleOAuthService.revoke_user_token(request.user)
Configuration
# settings.py
# Save tokens to database (default: True)
GOOGLE_OAUTH_SAVE_TOKENS_TO_DB = True
# Revoke tokens when user logs out (default: False)
GOOGLE_OAUTH_REVOKE_ON_LOGOUT = True
Legacy Session Token Storage
If you prefer session-based storage instead of database storage:
# settings.py
GOOGLE_OAUTH_SAVE_TOKENS_TO_DB = False # Disable database storage
GOOGLE_OAUTH_STORE_TOKENS = True # Enable session storage
Then access tokens in your views:
def my_view(request):
access_token = request.session.get("google_access_token")
refresh_token = request.session.get("google_refresh_token")
token_expiry = request.session.get("google_token_expiry")
# Use tokens to make Google API calls
# ...
Note: Session storage is less reliable and doesn't support automatic token refresh.
Extending User Creation
If you need to store additional user information (like google_id or picture), you can:
-
Create a custom user model:
from django.contrib.auth.models import AbstractUser class User(AbstractUser): google_id = models.CharField(max_length=255, blank=True) picture = models.URLField(blank=True)
-
Or create a user profile model:
class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) google_id = models.CharField(max_length=255, blank=True) picture = models.URLField(blank=True)
-
Override the UserService (recommended):
from django_googler.services import UserService as BaseUserService class CustomUserService(BaseUserService): @staticmethod def _create_new_user( email, name=None, given_name=None, family_name=None, google_id=None, picture=None, ): user = super()._create_new_user( email, name, given_name, family_name, google_id, picture ) # Store additional fields if google_id: user.google_id = google_id if picture: user.picture = picture user.save() return user
Architecture
Django Googler follows a clean service-layer architecture:
views.py- View layer (DRF and Django views)services.py- Business logic layerGoogleOAuthService- OAuth token processingUserService- User creation and managementOAuthFlowService- OAuth state management
platform_client.py- Google OAuth client wrapperdefaults.py- Configuration and settings
Configuration Reference
All settings are optional and have sensible defaults:
| Setting | Default | Description |
|---|---|---|
GOOGLE_OAUTH_CLIENT_ID |
"" |
Google OAuth Client ID (required) |
GOOGLE_OAUTH_CLIENT_SECRET |
"" |
Google OAuth Client Secret (required) |
GOOGLE_OAUTH_REDIRECT_URIS |
["http://localhost:8000/api/googler/callback"] |
Authorized redirect URIs |
GOOGLE_OAUTH_SCOPES |
["openid", "email", "profile"] |
OAuth scopes to request |
GOOGLE_OAUTH_SAVE_TOKENS_TO_DB |
True |
Save tokens to database (recommended) |
GOOGLE_OAUTH_STORE_TOKENS |
False |
Store tokens in session (legacy) |
GOOGLE_OAUTH_RETURN_TOKENS |
False |
Return Google tokens in API response |
GOOGLE_OAUTH_REVOKE_ON_LOGOUT |
False |
Revoke tokens when user logs out |
LOGIN_URL |
"/login/" |
Redirect URL on OAuth errors |
Rate Limiting
Django Googler includes built-in rate limiting for OAuth endpoints:
- Login endpoint: 10 requests per hour
- Callback endpoint: 20 requests per hour
You can customize these rates in your Django REST Framework settings:
# settings.py
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_RATES": {
"anon": "100/hour",
"user": "1000/hour",
}
}
Error Handling
The views handle various error scenarios:
| Error Code | Description |
|---|---|
oauth_init_failed |
Failed to initiate OAuth flow |
missing_code |
Authorization code not provided by Google |
invalid_state |
CSRF state verification failed |
no_email |
Google didn't provide an email address |
oauth_callback_failed |
General callback processing error |
Access errors via query parameters:
def login_view(request):
error = request.GET.get("error")
if error == "invalid_state":
messages.error(request, "Security check failed. Please try again.")
Google Cloud Console Setup
- Go to Google Cloud Console
- Create a new project or select existing one
- Enable the Google+ API and People API
- Go to Credentials → Create Credentials → OAuth 2.0 Client ID
- Configure Authorized redirect URIs:
- For local development:
http://localhost:8000/auth/google/callback/ - For production:
https://yourdomain.com/auth/google/callback/
- For local development:
- Copy the Client ID and Client Secret to your Django settings
License
MIT License - see LICENSE file for details
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues and questions, please use the GitHub issue tracker.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_googler-0.0.9.tar.gz.
File metadata
- Download URL: django_googler-0.0.9.tar.gz
- Upload date:
- Size: 59.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34382e3e3c47c203f2b2ebf561912fb52142732d0f8a324acc9e5f6b5ef8eb4f
|
|
| MD5 |
39240a7ef3ee5c16a4acc738033a45f9
|
|
| BLAKE2b-256 |
8d12de5bca9d563e898a5d5f8a84a73d7180e36c57f7618dc76c022f1d9198b8
|
Provenance
The following attestation bundles were made for django_googler-0.0.9.tar.gz:
Publisher:
main.yaml on jmitchel3/django-googler
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_googler-0.0.9.tar.gz -
Subject digest:
34382e3e3c47c203f2b2ebf561912fb52142732d0f8a324acc9e5f6b5ef8eb4f - Sigstore transparency entry: 621083774
- Sigstore integration time:
-
Permalink:
jmitchel3/django-googler@efdc0e1f70cc905c297ddda467187662638df3ce -
Branch / Tag:
refs/tags/v0.0.9 - Owner: https://github.com/jmitchel3
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
main.yaml@efdc0e1f70cc905c297ddda467187662638df3ce -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_googler-0.0.9-py3-none-any.whl.
File metadata
- Download URL: django_googler-0.0.9-py3-none-any.whl
- Upload date:
- Size: 29.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27e825f69ce6e44fd654765fe81cfdf2a1907368c056fee584b74b5b17247a83
|
|
| MD5 |
508e6006709d57c0aaa9db63792e5b22
|
|
| BLAKE2b-256 |
53af24be6187ec8f6263af1591b53f95861f51dde32872edb139b59b9f3433c0
|
Provenance
The following attestation bundles were made for django_googler-0.0.9-py3-none-any.whl:
Publisher:
main.yaml on jmitchel3/django-googler
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_googler-0.0.9-py3-none-any.whl -
Subject digest:
27e825f69ce6e44fd654765fe81cfdf2a1907368c056fee584b74b5b17247a83 - Sigstore transparency entry: 621083779
- Sigstore integration time:
-
Permalink:
jmitchel3/django-googler@efdc0e1f70cc905c297ddda467187662638df3ce -
Branch / Tag:
refs/tags/v0.0.9 - Owner: https://github.com/jmitchel3
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
main.yaml@efdc0e1f70cc905c297ddda467187662638df3ce -
Trigger Event:
push
-
Statement type: