Spaces:
Running
Running
Google Sign-In Client Integration Guide
Quick guide for frontend developers to integrate Google Sign-In with the APIGateway.
Setup
1. Get Your Google Client ID
Use the same GOOGLE_CLIENT_ID that's configured on the backend.
2. Add Google Identity Services Script
<script src="https://accounts.google.com/gsi/client" async defer></script>
Option A: One-Tap / Button Sign-In (Recommended)
<!DOCTYPE html>
<html>
<head>
<script src="https://accounts.google.com/gsi/client" async defer></script>
</head>
<body>
<!-- Google One Tap prompt -->
<div id="g_id_onload"
data-client_id="YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com"
data-callback="handleGoogleSignIn"
data-auto_prompt="false">
</div>
<!-- Sign In Button -->
<div class="g_id_signin"
data-type="standard"
data-size="large"
data-theme="outline"
data-text="sign_in_with"
data-shape="rectangular"
data-logo_alignment="left">
</div>
<script>
const API_BASE = 'https://your-api-gateway.com'; // Change this
async function handleGoogleSignIn(response) {
try {
// Send Google token to your backend
const res = await fetch(`${API_BASE}/auth/google`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id_token: response.credential,
temp_user_id: localStorage.getItem('temp_user_id') // optional
})
});
const data = await res.json();
if (data.success) {
// Store the access token
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('user', JSON.stringify({
user_id: data.user_id,
email: data.email,
name: data.name,
credits: data.credits
}));
console.log('Signed in!', data.is_new_user ? 'New user' : 'Existing user');
// Redirect or update UI
window.location.reload();
} else {
alert('Sign in failed: ' + (data.detail || 'Unknown error'));
}
} catch (error) {
console.error('Sign in error:', error);
alert('Sign in failed. Please try again.');
}
}
</script>
</body>
</html>
Option B: Programmatic Sign-In
const API_BASE = 'https://your-api-gateway.com';
// Initialize Google Sign-In
function initGoogleSignIn(clientId) {
google.accounts.id.initialize({
client_id: clientId,
callback: handleGoogleSignIn
});
// Render button in a container
google.accounts.id.renderButton(
document.getElementById('google-signin-btn'),
{ theme: 'outline', size: 'large', text: 'signin_with' }
);
}
// Handle the response
async function handleGoogleSignIn(response) {
const res = await fetch(`${API_BASE}/auth/google`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id_token: response.credential })
});
const data = await res.json();
if (data.success) {
localStorage.setItem('access_token', data.access_token);
}
}
// Call on page load
window.onload = () => initGoogleSignIn('YOUR_CLIENT_ID.apps.googleusercontent.com');
Making API Calls
After sign-in, use the access token for all API calls:
const API_BASE = 'https://your-api-gateway.com';
async function apiCall(endpoint, options = {}) {
const token = localStorage.getItem('access_token');
if (!token) {
throw new Error('Not signed in');
}
const response = await fetch(`${API_BASE}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (response.status === 401) {
// Token expired - need to sign in again
localStorage.removeItem('access_token');
window.location.href = '/login';
return;
}
return response.json();
}
// Examples
async function getCurrentUser() {
return apiCall('/auth/me');
}
async function generateText(prompt) {
return apiCall('/gemini/generate-text', {
method: 'POST',
body: JSON.stringify({ prompt })
});
}
async function checkJobStatus(jobId) {
return apiCall(`/gemini/job/${jobId}`);
}
API Endpoints Reference
| Endpoint | Method | Auth Required | Description |
|---|---|---|---|
/auth/google |
POST | β | Sign in with Google token |
/auth/me |
GET | β | Get current user info |
/auth/refresh |
POST | β | Refresh access token |
/gemini/generate-text |
POST | β | Generate text (costs 1 credit) |
/gemini/generate-video |
POST | β | Generate video (costs 1 credit) |
/gemini/job/{job_id} |
GET | β | Check job status |
Sign Out
function signOut() {
localStorage.removeItem('access_token');
localStorage.removeItem('user');
// Optionally call logout endpoint for audit
fetch(`${API_BASE}/auth/logout`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` }
});
// Revoke Google session
google.accounts.id.disableAutoSelect();
window.location.href = '/';
}
Error Handling
| Status | Meaning | Action |
|---|---|---|
| 401 | Token expired/invalid | Redirect to sign-in |
| 402 | Insufficient credits | Show "buy credits" prompt |
| 429 | Rate limited | Wait and retry |
async function apiCallWithErrorHandling(endpoint, options) {
const response = await apiCall(endpoint, options);
if (response.status === 402) {
alert('You have run out of credits!');
return null;
}
return response;
}
React Example
import { useEffect, useState } from 'react';
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
// Check if already signed in
const token = localStorage.getItem('access_token');
if (token) {
fetch('/auth/me', {
headers: { 'Authorization': `Bearer ${token}` }
})
.then(r => r.json())
.then(setUser)
.catch(() => localStorage.removeItem('access_token'));
}
// Initialize Google Sign-In
window.handleGoogleSignIn = async (response) => {
const res = await fetch('/auth/google', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id_token: response.credential })
});
const data = await res.json();
if (data.success) {
localStorage.setItem('access_token', data.access_token);
setUser(data);
}
};
}, []);
if (!user) {
return (
<div>
<div id="g_id_onload"
data-client_id="YOUR_CLIENT_ID"
data-callback="handleGoogleSignIn" />
<div className="g_id_signin" data-type="standard" />
</div>
);
}
return <div>Welcome, {user.name}! Credits: {user.credits}</div>;
}