How to Implement Supabase Auth with Google OAuth-Only Sign-In
The application restricts authentication to Google OAuth exclusively by configuring the Supabase client with persistent sessions and implementing a dedicated signInWithOAuth flow that specifies provider: 'google', while server-side validation through getAuthContext ensures only valid Google-authenticated users access protected resources.
This guide explains how the freestylefly/awesome-gpt-image-2 repository implements a Google-only authentication strategy using Supabase Auth. By eliminating email/password options and restricting the OAuth provider to Google, the application streamlines user onboarding while maintaining secure session management across client and server environments.
Initializing the Supabase Client with Session Persistence
The front-end establishes the foundation for Google-only authentication in src/supabaseClient.js by creating a Supabase client instance that automatically manages token refresh and session persistence. This configuration ensures users remain authenticated across page reloads without manual intervention.
// src/supabaseClient.js
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
autoRefreshToken: true,
detectSessionInUrl: true,
persistSession: true
}
});
The detectSessionInUrl: true option is critical for OAuth flows, as it automatically extracts the authentication tokens from the URL when Google redirects back to the application. The persistSession: true setting stores these tokens in local storage, enabling persistent login states.
Implementing Google-Only OAuth Sign-In
The UI enforces the Google-only restriction by rendering a dedicated sign-in button that explicitly calls signInWithOAuth with the Google provider. Located in src/main.jsx, this implementation prevents alternative authentication methods by simply not providing UI elements for email/password entry.
// src/main.jsx (excerpt)
const handleGoogleSignIn = async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: window.location.origin }
});
if (error) console.error('Google sign-in error:', error);
};
By hardcoding provider: 'google' and omitting any other provider options, the codebase ensures that signInWithPassword or other authentication methods remain unreachable through the user interface. The redirectTo parameter guarantees users return to the application root after Google completes the OAuth handshake.
Managing Authentication State Changes
After successful Google authentication, the application monitors session state using Supabase's real-time auth listeners. This pattern updates the React component state whenever the user's authentication status changes, ensuring the UI reflects the current login state immediately.
supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
});
This listener handles both sign-in and sign-out events, as well as automatic token refreshes configured in the client initialization. The session object contains the JWT access token required for subsequent API requests to protected endpoints.
Server-Side Verification with getAuthContext
All protected API routes rely on the getAuthContext function exported from api/_lib/supabase.js to validate incoming requests. This utility extracts Bearer tokens from the Authorization header and verifies them against Supabase's authentication service before executing route handlers.
// api/_lib/supabase.js
export async function getAuthContext(req, { allowAnonymous = false } = {}) {
const token = getBearerToken(req);
if (!token) return allowAnonymous
? { user: null, profile: null }
: { error: 'AUTH_REQUIRED', status: 401 };
const { data, error } = await client.auth.getUser(token);
if (error) return { error: 'AUTH_REQUIRED', status: 401 };
const profile = await ensureProfileForUser(data.user);
return { user: data.user, profile, token, client };
}
The function returns a standardized context object containing the authenticated user, their profile, the raw token, and a server-side Supabase client instance. Routes using this helper automatically reject unauthenticated requests with a 401 status code unless explicitly configured to allow anonymous access.
Creating User Profiles from Google Metadata
When a user authenticates via Google for the first time, the ensureProfileForUser function in api/_lib/supabase.js automatically provisions a database record using metadata provided by Google's OAuth service. This eliminates manual profile creation and ensures consistency between Google Account data and the application's user records.
const googleName = metadata.full_name || metadata.name || null;
const googleAvatar = metadata.avatar_url || metadata.picture || null;
const payload = {
id: user.id,
email,
full_name: existingProfile?.full_name || googleName,
avatar_url: googleAvatar || existingProfile?.avatar_url,
// …
};
The logic prioritizes existing profile data while falling back to Google-provided attributes, accommodating scenarios where users might update their information within the application independently of their Google Account. The schema for these profiles is defined in supabase/migrations/20260512090000_google_account_center.sql.
Summary
- Client Configuration: The Supabase client in
src/supabaseClient.jsenables automatic token refresh and session persistence to maintain Google authentication across page reloads. - Exclusive Provider Restriction: Hardcoding
provider: 'google'insrc/main.jsxenforces the OAuth-only policy while eliminating password-based authentication vectors. - Server Validation: The
getAuthContextutility inapi/_lib/supabase.jsvalidates JWT tokens from theAuthorizationheader on every protected API request. - Automatic Provisioning: User profiles are dynamically created from Google OAuth metadata including
full_name,avatar_url, and email address upon first sign-in. - Security Enforcement: The combination of dashboard-level Supabase settings and client-side implementation ensures no alternative authentication providers can access the system.
Frequently Asked Questions
How does the application prevent users from signing in with email and password?
The application eliminates email/password authentication by simply not implementing the UI components or API calls required for password-based sign-in. The codebase exclusively uses supabase.auth.signInWithOAuth({ provider: 'google' }), and the Supabase project dashboard has all other authentication providers disabled, making Google the sole available option.
What happens to the session when a user closes and reopens their browser?
Sessions persist across browser restarts because the Supabase client initializes with persistSession: true, which stores the authentication tokens in local storage. The autoRefreshToken: true setting ensures that expired tokens are automatically refreshed in the background, allowing users to remain logged in indefinitely unless they explicitly sign out.
How does the server verify that a request comes from an authenticated Google user?
Protected API routes call getAuthContext(req), which extracts the JWT from the Authorization: Bearer <token> header and validates it using client.auth.getUser(token). This verification process confirms the token's authenticity with Supabase's authentication servers before allowing access to protected resources.
Where is the user profile data stored and how is it structured?
User profiles are stored in the Supabase database according to the schema defined in supabase/migrations/20260512090000_google_account_center.sql. The ensureProfileForUser function populates fields including id, email, full_name, and avatar_url by mapping Google OAuth metadata to the database schema upon the user's first authentication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →