Skip to content

feat: add OAuthGate components for user-level OAuth connections#17

Open
rishikesh-major wants to merge 10 commits intomainfrom
rishikesh/dev
Open

feat: add OAuthGate components for user-level OAuth connections#17
rishikesh-major wants to merge 10 commits intomainfrom
rishikesh/dev

Conversation

@rishikesh-major
Copy link
Collaborator

Summary

Adds <OAuthGate> and <OAuthGateScreen> components that deployed apps use to gate access behind user-level OAuth connections (e.g., Google Calendar).

  • <OAuthGate> is a server component that checks go-api's /internal/user-oauth/status endpoint during SSR to see if the current user has connected all required OAuth providers
  • If any are missing, it renders <OAuthGateScreen> (a client component) with branded connect buttons instead of the app content
  • Once all providers are connected, it renders {children} normally
  • Handles both standalone (direct URL) and iframe (dashboard) access automatically
  • OAuth flow uses a popup window — the callback page sends postMessage back to close the popup and refresh the gate

Usage

import { OAuthGate } from "@/components/oauth-gate";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <OAuthGate>{children}</OAuthGate>
      </body>
    </html>
  );
}

Companion PR

🤖 Generated with Claude Code

rishikesh-major and others added 10 commits March 3, 2026 08:52
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The deployed app handles OAuth entirely on its own via the OAuthGate
server component and x-major-user-jwt. No need to delegate to the
parent shell when running inside the dashboard iframe.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
RESOURCE_API_URL is pod-reachable for server-side status checks.
RESOURCE_API_BROWSER_URL is browser-reachable for OAuth redirect links.
Locally these differ (host.docker.internal vs localhost).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move JSX out of try/catch in oauth-gate.tsx (react-hooks/error-boundaries)
- Use lazy useState initializer instead of useEffect+setState in
  oauth-gate-screen.tsx (react-hooks/set-state-in-effect)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The OAuthGate sign-in button was navigating directly to the go-api
auth-url endpoint, which returns JSON. Now it fetches the endpoint,
extracts the actual Google OAuth URL, and redirects to that.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The auth-url endpoint requires session auth, which isn't available from
the deployed app's browser context. Move URL resolution to the server
component using a new internal JWT-authenticated endpoint, so the client
receives actual Google OAuth URLs it can navigate to directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Google blocks OAuth consent in iframes (403), and the redirect flow
had returnUrl issues. Switch to popup-only: opens Google consent in a
popup window, listens for postMessage/close, then reloads to re-check
status via SSR. Works uniformly in both dashboard iframe and standalone.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant