Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Google Sso Setup

ASecurity

Wire Sign in with Google end-to-end: Google Cloud OAuth client + consent screen + redirect URIs + scopes, then via Supabase Auth's Google provider (and a note on the Auth.js / direct path). Step-by-step with verification checkpoints.

7 stars
0 votes
0 copies
0 views
Added 9/23/2026
ai-agentsjavascriptgojavanextjstestingdebugginggitapibackendsecurity

Works with

cliapi

Security Analysis

A92/100
mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned 9/23/2026

$npx -y skills add mcorbett51090/RavenClaude --skill google-sso-setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Google Sso Setup?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Google Sso Setup
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mcorbett51090-google-sso-setup/badge)](https://www.skillsdirectory.com/skills/mcorbett51090-google-sso-setup)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: google-sso-setup
description: "Wire Sign in with Google end-to-end: Google Cloud OAuth client + consent screen + redirect URIs + scopes, then via Supabase Auth's Google provider (and a note on the Auth.js / direct path). Step-by-step with verification checkpoints."
---

# Skill: google-sso-setup

> **Invoked by:** the `auth-identity` team's identity-setup agent. Also consulted by `ravenclaude-core/security-reviewer` when reviewing any OAuth client registration change.
>
> **When to invoke:** new project needs Google SSO; switching from password auth to Google-first; adding Google as a second provider to an existing Supabase project; debugging a redirect-URI mismatch or consent-screen error.
>
> **Output:** working Google SSO flow (OAuth client registered, Supabase provider enabled, redirect URIs set, scopes justified, test login passes) + security checklist signed off.

---

## Boundary

This skill **authenticates the person** (verifies their Google identity). It does not scope data access. Once the user is authenticated and `auth.uid()` is available, data-row scoping hands off to the `data-platform` plugin's RLS skills (`rls-policy-authoring`, `jwt-embed-issuance`). Do not duplicate RLS or embed-JWT mechanics here.

---

## Overview: two paths

| Path | When to use |
|---|---|
| **Supabase Auth → Google provider** (recommended) | You are already using Supabase (Postgres + RLS). One config screen, managed token storage, `auth.uid()` available directly in RLS policies. |
| **Auth.js (formerly NextAuth) + Google provider** | You need framework-level flexibility (multiple providers, custom session shape, non-Supabase backend). More code, more config. |
| **Google Identity Services SDK (direct)** | Rare. Only when you want maximum control and are not using any managed auth layer. Avoid unless there is a strong reason. |

For this stack (Next.js + Supabase), default to the **Supabase Auth** path.

---

## Step 1 — Google Cloud: create the OAuth client

> **Platform:** [console.cloud.google.com](https://console.cloud.google.com) [unverified — verify against current console UI]

1. Select or create a Google Cloud project.
2. Navigate to **APIs & Services → OAuth consent screen**.
3. Fill in the consent screen:
   - **App name, user support email, developer contact email** — required.
   - **Scopes:** add only what you need. For "Sign in with Google" you need `openid`, `email`, `profile` — nothing more. Adding extra scopes (Drive, Calendar, etc.) triggers extended verification and delays publishing.
   - **Authorized domains:** add your app's root domain (e.g., `example.com`). This controls what redirect URIs are allowed.
   - **Publishing status:** leave as **Testing** during development. Move to **Production** before launch (required for users outside your test-user list).
4. Navigate to **Credentials → Create Credentials → OAuth 2.0 Client ID**.
5. Application type: **Web application**.
6. **Authorized JavaScript origins:** your app's origin(s), e.g. `https://app.example.com` (and `http://localhost:3000` for local dev).
7. **Authorized redirect URIs:** this is the most common source of errors — see Step 3 for the exact values.
8. Save. Copy **Client ID** and **Client Secret** — you will need them in Step 2.

> **Verification checkpoint:** the consent screen shows no "needs verification" banner for the three scopes above (`openid`, `email`, `profile`). If it does, you added a sensitive scope by mistake.

---

## Step 2 — Supabase: enable the Google provider

> [unverified — verify against current Supabase dashboard UI at supabase.com/docs/guides/auth/social-login/auth-google]

1. Open the Supabase dashboard for your project.
2. Go to **Authentication → Providers → Google**.
3. Toggle **Enable Sign in with Google**.
4. Paste the **Client ID** and **Client Secret** from Step 1.
5. The Supabase dashboard will show you the **callback URL** you must add to Google Cloud. It looks like:
   `https://<project-ref>.supabase.co/auth/v1/callback`
   Copy it for Step 3.
6. Save.

---

## Step 3 — Google Cloud: set the redirect URI

Back in Google Cloud Console → Credentials → your OAuth client:

- Add the Supabase callback URL from Step 2 to **Authorized redirect URIs**:
  `https://<project-ref>.supabase.co/auth/v1/callback`
- For local development also add:
  `http://localhost:54321/auth/v1/callback` (Supabase local emulator default) [unverified — confirm your local port]
- Save.

> **Common error:** `redirect_uri_mismatch` — the URI in the OAuth flow does not exactly match one in the authorized list. Trailing slashes, `http` vs `https`, and port numbers all matter. Copy-paste exactly.

---

## Step 4 — Next.js: wire the sign-in call

The following is a conceptual sketch. **Security-review before shipping any auth code to production.**

```tsx
// lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
  );
}
```

```tsx
// components/GoogleSignInButton.tsx
"use client";
import { createClient } from "@/lib/supabase/client";

export function GoogleSignInButton() {
  const supabase = createClient();

  async function signInWithGoogle() {
    await supabase.auth.signInWithOAuth({
      provider: "google",
      options: {
        redirectTo: `${location.origin}/auth/callback`,
        // scopes default to openid, email, profile — do not expand unless required
      },
    });
  }

  return <button onClick={signInWithGoogle}>Sign in with Google</button>;
}
```

```tsx
// app/auth/callback/route.ts  (Next.js App Router)
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  const requestUrl = new URL(request.url);
  const code = requestUrl.searchParams.get("code");
  const next = requestUrl.searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = cookies();
    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      { cookies: { getAll: () => cookieStore.getAll(), setAll: (c) => c.forEach(({ name, value, options }) => cookieStore.set(name, value, options)) } },
    );
    await supabase.auth.exchangeCodeForSession(code);
  }

  return NextResponse.redirect(new URL(next, requestUrl.origin));
}
```

> **Security note:** tokens are stored in HttpOnly cookies by `@supabase/ssr` — do not extract them to localStorage. See `session-and-token-management` skill and the `never-store-tokens-in-localstorage` best-practice.

---

## Step 5 — Retrieve the session and `auth.uid()`

```tsx
// app/dashboard/page.tsx (server component)
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export default async function DashboardPage() {
  const cookieStore = cookies();
  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    { cookies: { getAll: () => cookieStore.getAll(), setAll: () => {} } },
  );

  const { data: { user } } = await supabase.auth.getUser();
  if (!user) redirect("/login");

  // user.id == auth.uid() in Postgres RLS policies
  // Pass to data-platform RLS via the Supabase client — the JWT in the cookie
  // carries auth.uid() automatically.
  return <div>Welcome, {user.email}</div>;
}
```

The authenticated user's `user.id` maps to `auth.uid()` in Postgres RLS policies. Data scoping (which rows this user can read) is governed by the `data-platform` plugin's `rls-policy-authoring` skill — not by this plugin.

---

## Scope discipline

| Scope | When to include |
|---|---|
| `openid` | Always — required for OIDC / ID token issuance |
| `email` | Always — your app needs the user's email |
| `profile` | Usually — name + avatar |
| `https://www.googleapis.com/auth/drive` | Only if your app genuinely reads/writes Google Drive. Triggers Google's extended verification. |
| Any other Google API scope | Only if you have a concrete feature requirement. Minimise scope. |

---

## Auth.js path (alternative)

If you are not using Supabase or need framework flexibility:

1. `npm install next-auth` [unverified — confirm current package name; may be `next-auth@beta` for v5]
2. Configure `[...nextauth]/route.ts` with `GoogleProvider({ clientId, clientSecret })`.
3. The redirect URI registered in Google Cloud is: `https://app.example.com/api/auth/callback/google`.
4. Use `getServerSession` / `auth()` (v5) in server components.
5. For cookie storage of the session, use the `cookies` option with HttpOnly flags.

The token-storage and PKCE mechanics in `oauth-oidc-flow-design` and `session-and-token-management` skills apply regardless of which path you take.

---

## Anti-patterns this skill flags

- Redirect URI contains a trailing slash when Google expects none (or vice versa) — causes `redirect_uri_mismatch`
- Consent screen left in **Testing** mode at launch — external users cannot sign in (blocked after 100 test-user invitations)
- Client Secret exposed in front-end code or checked into git — must live in a server-side env var
- Scopes wider than `openid email profile` without a documented feature requirement
- Token stored in `localStorage` after the OAuth callback — use HttpOnly cookies (Supabase SSR handles this automatically)
- `signInWithOAuth` called server-side — it triggers a browser redirect; call it from a client component or a route handler
- PKCE disabled — Supabase Auth enables it by default; do not disable it [unverified — confirm PKCE default in current Supabase Auth version]

---

## Verification checklist

- [ ] OAuth client created in the correct Google Cloud project
- [ ] Redirect URIs match exactly (no trailing slash, correct scheme)
- [ ] Consent screen in **Production** mode before external users onboard
- [ ] Scopes limited to `openid email profile`
- [ ] `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY` in `.env.local` (never committed)
- [ ] `SUPABASE_SERVICE_ROLE_KEY` (if used) only in server-side env, never `NEXT_PUBLIC_`
- [ ] Test sign-in completes; session returned; `user.id` non-null
- [ ] `auth.uid()` resolves correctly in a test RLS query
- [ ] Security review completed before production deploy (see `ravenclaude-core/security-reviewer`)

---

## See also

- Skill: [`../oauth-oidc-flow-design/SKILL.md`](../oauth-oidc-flow-design/SKILL.md) — why Authorization Code + PKCE, not Implicit; flow selection by client type
- Skill: [`../session-and-token-management/SKILL.md`](../session-and-token-management/SKILL.md) — HttpOnly cookie storage, refresh rotation, logout
- Skill: [`../protect-spa-and-api/SKILL.md`](../protect-spa-and-api/SKILL.md) — route guards, API token verification, CORS + CSRF
- Template: [`../../templates/supabase-google-sso-setup.md`](../../templates/supabase-google-sso-setup.md) — copy-paste walkthrough
- Best-practice: [`../../best-practices/prefer-managed-auth-over-rolling-your-own.md`](../../best-practices/prefer-managed-auth-over-rolling-your-own.md)
- data-platform: [`../../../data-platform/skills/rls-policy-authoring/SKILL.md`](../../../data-platform/skills/rls-policy-authoring/SKILL.md) — how `auth.uid()` drives data scoping (data authorization, not auth-identity's concern)
- Security escalation: [`../../../ravenclaude-core/agents/security-reviewer.md`](../../../ravenclaude-core/agents/security-reviewer.md) — mandatory review for any auth code going to production

Attribution

mcorbett51090mcorbett51090
View sourceSee grades on GitHubMore from mcorbett51090 →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698461 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →