Skip to main content

Django Googler

Simple Google OAuth authentication for Django. Returns JWT tokens for your API.

What It Does

  1. User clicks "Sign in with Google"
  2. Google handles authentication
  3. Your Django app gets JWT tokens + user info
  4. Use JWT tokens for authenticated API requests

Installation

uv add django-googler

or

pip install django-googler

Quick Setup

1. Create a new Google Auth Platform Client

  • Go to Google Cloud Console
  • Navigate to Google Auth Platform
  • Click Create Client
  • Select Web Application
  • Enter a name for your client
  • In Javascript Origins, enter the URLs of your frontend(s) (e.g. http://localhost:3000, http://localhost:8000, http://localhost:8888, etc.)
  • Enter the redirect URIs for your client:
    • http://localhost:8000/api/auth/google/callback/
    • http://localhost:8000/auth/google/callback/
    • http://127.0.0.1:8000/api/auth/google/callback/
    • http://127.0.0.1:8000/auth/google/callback/
  • Click Create
  • Copy the Client ID and Client Secret and update your .env file with:
GOOGLE_OAUTH_CLIENT_ID=your-client-id
GOOGLE_OAUTH_CLIENT_SECRET=your-client-secret

2. Update Django configuration in settings.py

INSTALLED_APPS = [
    # ...
    "rest_framework",
    "rest_framework_simplejwt",
    "rest_framework_simplejwt.token_blacklist",  # Optional: for logout
    "django_googler",
]

# Get these from Google Cloud Console
GOOGLE_OAUTH_CLIENT_ID = "your-client-id"
GOOGLE_OAUTH_CLIENT_SECRET = "your-client-secret"

# change in production to valid redirect URIs
GOOGLE_OAUTH_REDIRECT_URIS = [
    "http://localhost:8000/api/googler/callback",
    "http://localhost:8000/auth/google/callback/",
]

# Optional: Save OAuth tokens to database
# Default: True
GOOGLE_OAUTH_SAVE_TOKENS_TO_DB = True
# Optional: Request additional Google API scopes
# Defaults: <below>
GOOGLE_OAUTH_SCOPES = [
    "openid",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile",
]

3. Add URLs

# urls.py
from django.urls import path, include

urlpatterns = [
    # Django Rest Framework OAuth API views (if using DRF)
    path("api/auth/", include("django_googler.urls.api")),
    # Standard Django OAuth views with or without DRF)
    path("auth/", include("django_googler.urls.default")),
]

Both urls are optional, but you should use at least one of them.

These URLs provide the following:

Django Rest Framework API URLs:

  • GET /api/auth/google/login/ - Get Google OAuth URL
  • POST /api/auth/google/refresh/ - Refresh JWT tokens
  • POST /api/auth/google/callback/ - Exchange code for JWT tokens
  • POST /api/auth/google/logout/ - Logout (requires JWT tokens)
  • GET /api/auth/me/ - Get current user (requires JWT tokens)

Standard Django URLs:

  • GET /auth/google/login/ - To automatically start Google OAuth which will automatically redirect you to /auth/google/callback/ then to your LOGIN_REDIRECT_URL (if successful) or back to your LOGIN_URL (if unsuccessful)
  • GET /auth/google/callback/ - To handle Google's callback
  • To logout you'll use a standard Django logout view or logout method to end the User's session

4. Run Migrations

python manage.py migrate

Usage

API Examples:

curl http://localhost:8000/api/auth/google/login/

Yields:

{
  "authorization_url": "https://accounts.google.com/...",
  "state": "..."
}

Opening authorization_url in a new tab will start the Google OAuth flow and automatically redirect you to /api/auth/google/callback/. If you set DJANGO_GOOGLER_ALLOW_GET_ON_DRF_CALLBACK = True in settings.py, your automatic redirect to /api/auth/googler/callback/ will automatically provider your auth tokens in the response such as:

{
  "access": "eyJ0eXAiOiJKV1Q...",  // JWT access token (short-lived)
  "refresh": "eyJ0eXAiOiJKV1Q...", // JWT refresh token (long-lived)
  "user": {
    "id": 1,
    "email": "user@example.com",
    "username": "user",
    "first_name": "John",
    "last_name": "Doe"
  }
}

From here you can do an authenticated request to /api/auth/me/ to get the user's information:

curl http://localhost:8000/api/auth/me/ \
  -H "Authorization: Bearer <access_token>"

To refresh the access token, you can use the /api/auth/google/refresh/ endpoint:

curl -X POST http://localhost:8000/api/auth/google/refresh/ \
  -H "Content-Type: application/json" \
  -d '{"refresh": "<refresh_token>"}'

This is a standard JWT refresh endpoint provided by rest_framework_simplejwt with TokenRefreshView.

Frontend Flow

1. Get Google OAuth URL

const redirect_uri = 'http://localhost:3000/auth/callback';
const apiBaseUrl = 'http://localhost:8000';
const loginApiEndpoint = `${apiBaseUrl}/api/auth/google/login/`;
const requestUrl = `${loginApiEndpoint}?redirect_uri=${redirect_uri}`;
const response = await fetch(requestUrl);
const data = await response.json();
// data = { "authorization_url": "https://accounts.google.com/...", "state": "..." }

// Redirect user to Google
window.location.href = data.authorization_url;

2. Handle Google's Callback

After Google redirects back to your frontend with a code and state:

// Get the callback data from the current URL
const currentUrl = new URL(window.location.href);
const googleCallbackData = Object.fromEntries(currentUrl.searchParams);

// Send the callback data to the backend
const apiBaseUrl = 'http://localhost:8000';
const callbackApiEndpoint = `${apiBaseUrl}/api/auth/google/callback/`;
const response = await fetch(callbackApiEndpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(googleCallbackData)
});

const responseData = await response.json();
/* responseData = {
  "access": "eyJ0eXAiOiJKV1Q...",  // JWT access token (short-lived)
  "refresh": "eyJ0eXAiOiJKV1Q...", // JWT refresh token (long-lived)
  "user": {
    "id": 1,
    "email": "user@example.com",
    "username": "user",
    "first_name": "John",
    "last_name": "Doe"
  }
} */

// Save tokens
localStorage.setItem('access_token', responseData.access);
localStorage.setItem('refresh_token', responseData.refresh);

3. Make Authenticated Requests

const apiBaseUrl = 'http://localhost:8000';
const meApiEndpoint = `${apiBaseUrl}/api/auth/me/`;
const response = await fetch(meApiEndpoint, {
  headers: {
    'Authorization': `Bearer ${localStorage.getItem('access_token')}`
  }
});

const responseData = await response.json();
/* responseData = {
  "id": 1,
  "email": "user@example.com",
  "username": "user",
  "first_name": "John",
  "last_name": "Doe"
} */

4. Logout

const apiBaseUrl = 'http://localhost:8000';
const logoutApiEndpoint = `${apiBaseUrl}/api/auth/logout/`;
const response = await fetch(logoutApiEndpoint, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${localStorage.getItem('access_token')}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    refresh: localStorage.getItem('refresh_token')
  })
});

localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');

Configuration

Required Settings

GOOGLE_OAUTH_CLIENT_ID = "your-client-id"
GOOGLE_OAUTH_CLIENT_SECRET = "your-client-secret"

Optional Settings

# Return Google tokens in callback response (for calling Google APIs from frontend)
# Default: False
GOOGLE_OAUTH_RETURN_TOKENS = False

# Revoke Google access on logout
# Default: False
GOOGLE_OAUTH_REVOKE_ON_LOGOUT = False

# Save Google OAuth tokens to database (for backend Google API calls)
# Default: True
GOOGLE_OAUTH_SAVE_TOKENS_TO_DB = True

# Request additional Google API scopes
# Default: ["openid", "email", "profile"]
GOOGLE_OAUTH_SCOPES = [
    "openid",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile",
    # "https://www.googleapis.com/auth/calendar",  # Add if needed
]

Google Cloud Setup

For Development:

  1. Go to Google Cloud Console
  2. Create a project
  3. Go to Google Auth Platform
  4. Navigate to Clients > +Create Client

For Development use:

  • Application type: Web application
  • Name: Django Googler Dev
  • Authorized redirect URIs:
    • http://localhost:8000/api/auth/google/callback/
    • http://localhost:8000/auth/google/callback/ (frontend handler for Django-based frontend)
    • http://localhost:3000/auth/google/callback/ (frontend handler for React, Next.js or Vue)
    • Any others you might need during development

For Production use:

  • Application type: Web application
  • Name: Django Googler Prod
  • Redirect URIs:
    • https://yourdomain.com/api/auth/google/callback/
    • https://yourdomain.com/auth/google/callback/ (frontend handler for Django or Next.js/React/Vue frontend)
    • Any others you might need (adding more is fine especially if you have multiple frontend frameworks)

After you configure it, click Create and for each environment (prod/dev) grab:

  • Client ID (such as django-googler-dev.apps.googleusercontent.com and django-googler-prod.apps.googleusercontent.com)
  • Client Secret

For dev, update your .env file with:

GOOGLE_OAUTH_CLIENT_ID=django-googler-dev.apps.googleusercontent.com
GOOGLE_OAUTH_CLIENT_SECRET=your-dev-client-secret

For prod, update your runtime secrets with:

GOOGLE_OAUTH_CLIENT_ID=django-googler-prod.apps.googleusercontent.com
GOOGLE_OAUTH_CLIENT_SECRET=your-prod-client-secret

Making Google API Calls

If your backend needs to call Google APIs on behalf of users:

from django_googler.services import GoogleOAuthService


def my_view(request):
    # Get valid access token (auto-refreshes if expired)
    access_token, expiry = GoogleOAuthService.get_valid_token(request.user)

    if access_token:
        import requests

        headers = {"Authorization": f"Bearer {access_token}"}
        response = requests.get(
            "https://www.googleapis.com/calendar/v3/calendars/primary/events",
            headers=headers,
        )
        return response.json()

Using Django Views (Instead of API)

If you prefer browser redirects over API calls:

# urls.py
urlpatterns = [
    path("auth/", include("django_googler.urls.default")),
]

Then in your template:

<a href="{% url 'django_googler:google-login' %}?next=/dashboard/">
    Sign in with Google
</a>

Users will be redirected to Google and back, then logged into Django's session.

Architecture

  • Views - Handle OAuth flow and return JWT tokens
  • Services - Business logic for OAuth, users, and tokens
  • Models - Store Google OAuth tokens in database

License

MIT License

Support

GitHub Issues

Metadata

Release files for django-googler 0.0.20

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-googler 0.0.20
File Size Uploaded Provenance
django_googler-0.0.20.tar.gz 65.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-googler 0.0.20
File Interpreter ABI Platform
django_googler-0.0.20-py3-none-any.whl Python 3 none any Details

Total release size: 101.1 kB

Release files / django_googler-0.0.20.tar.gz

Download URL django_googler-0.0.20.tar.gz
Size 65.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b8b67147fde17eaad909fa656768108c4c75d0f5125c5d27a2a723db7e92b38a
BLAKE2b-256 checksum
How to use checksums
d01602e1a3c4ebccb216663b5e97c7e8d8ec8121f295bfd0cdcd80a19803a540
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2025.

Transparency log

Release files / django_googler-0.0.20-py3-none-any.whl

Download URL django_googler-0.0.20-py3-none-any.whl
Size 35.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5a708393d9674514a5c5f643e4aff0290e9d8731335983099c69c6030e9b40f0
BLAKE2b-256 checksum
How to use checksums
4e346bad8e30d72b3a00350e688ec8dc111b72bb028f27a1e8c6405694345f0c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2025.

Transparency log

Security for django-googler 0.0.20

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_googler-0.0.20.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2025.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page