Skip to content

Google

Google’s flow is the simpler of the two providers supported today. Your frontend handles sign-in entirely through Google’s own UI, gets back a signed ID token, and your backend verifies that token and trades it for your own JWTs. There’s no redirect back to your server and no state parameter to manage.

This page assumes you’ve already finished the shared setup in Getting Started.

  1. The user clicks “Continue with Google” on your frontend.
  2. Google’s script handles the sign-in prompt and verifies the user directly with Google - your code never sees a password.
  3. Google calls your callback with a signed ID token.
  4. Your frontend sends that token to POST /api/social-auth/google/login/.
  5. The backend verifies the token with Google, creates or looks up the user, and returns JWT access and refresh tokens.
  1. Open the Google Cloud Console.
  2. Create a project, or select an existing one.
  3. Go to APIs & Services → Credentials.
  4. Click Create Credentials → OAuth client ID, and choose Web application as the type.
  5. Under Authorized JavaScript origins, add every origin your frontend runs on - http://localhost:5173 for local dev, your production domain, and so on.
  6. Copy the Client ID. This flow doesn’t use a client secret.
# settings.py
GOOGLE_CLIENT_ID = "your-google-client-id"

This is the only credential Google needs. As covered in Getting Started, the provider switches on automatically once this is set.

# urls.py
from django.urls import path, include
urlpatterns = [
path("api/social-auth/", include("django_social_auth_rest.urls.google")),
]

This works the same regardless of framework: load the Google Identity Services script once, render the button, and forward the resulting token to your backend.

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Google OAuth Test</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://accounts.google.com/gsi/client" async defer></script>
</head>
<body class="bg-zinc-950 text-zinc-100">
<div class="min-h-screen flex items-center justify-center px-4">
<div class="w-full max-w-sm rounded-lg border border-zinc-800 bg-zinc-900 p-6 space-y-4">
<h1 class="text-xl font-semibold text-center">Google OAuth Test</h1>
<div id="google-button" class="flex justify-center"></div>
<pre id="status" class="text-xs text-zinc-400 whitespace-pre-wrap break-all"></pre>
</div>
</div>
<script>
const GOOGLE_CLIENT_ID = "YOUR_GOOGLE_CLIENT_ID";
const BACKEND_BASE_URL = "http://localhost:8000";
const statusEl = document.getElementById("status");
function logStatus(label, data) {
statusEl.textContent = `${label}\n${JSON.stringify(data, null, 2)}`;
}
function initGoogleSignIn() {
google.accounts.id.initialize({
client_id: GOOGLE_CLIENT_ID,
callback: handleCredentialResponse,
});
google.accounts.id.renderButton(document.getElementById("google-button"), {
theme: "outline",
size: "large",
});
}
async function handleCredentialResponse({ credential }) {
try {
const response = await fetch(`${BACKEND_BASE_URL}/api/social-auth/google/login/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: credential }),
});
const data = await response.json();
if (!response.ok) {
logStatus("Google sign-in failed", data);
return;
}
logStatus("Signed in", data);
} catch (error) {
logStatus("Network error", { message: error.message });
}
}
window.addEventListener("load", initGoogleSignIn);
</script>
</body>
</html>

To link an already-signed-in user to a Google account instead of logging in, render the same button on an account settings page and point the fetch call at /api/social-auth/google/link/, with the user’s existing access token in the Authorization header. The request body is identical.

POST /api/social-auth/google/login/
Content-Type: application/json
{
"token": "<GOOGLE_ID_TOKEN>"
}

Response:

{ "access": "<JWT_ACCESS_TOKEN>", "refresh": "<JWT_REFRESH_TOKEN>" }

Logs the user in if a matching Google account is already linked, or creates a new user and link if this is the first time. No authentication required.

Requires authentication.

POST /api/social-auth/google/link/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Content-Type: application/json
{
"token": "<GOOGLE_ID_TOKEN>"
}

Returns 204 No Content on success. Fails if that Google account is already linked to a different user.

Requires authentication.

POST /api/social-auth/google/unlink/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Content-Type: application/json
{
"password": "<USER_PASSWORD>"
}

Returns 204 No Content on success.

Every failure comes back as a 400. Where the message appears in the response body depends on what failed:

What happenedResponse body
Invalid or expired Google token{"message": ["Google authentication could not be completed."]}
Google account email is not verified{"message": ["Your Google account email address is not verified."]}
Account is soft-deleted{"message": ["This account is no longer available."]}
Google account already linked to another user{"message": ["This Google account is already linked to another user."]}
Unlink: wrong password{"non_field_errors": ["Incorrect password."]}
Unlink: no linked Google account found{"non_field_errors": ["No linked google account found."]}