-
Notifications
You must be signed in to change notification settings - Fork 0
Migrate from better auth to workos for SSO integration #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1d5eab6
759a211
ddd1915
450caaa
c556d73
a5381fc
01d371f
736de84
f8267db
9420802
a31b5ed
4fcf379
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| --- | ||
| trigger: always_on | ||
| --- | ||
|
|
||
| ## Architecture & Priorities | ||
|
|
||
| - This is a PoC: prioritize developer speed and clarity over abstraction. | ||
| - Treat all backends as APIs; do not couple services together. | ||
| - The AI service is stateless and must not call application APIs directly. | ||
| - always use pnpm and pnpx for package management | ||
|
|
||
|
|
||
| ## Monorepo Structure | ||
|
|
||
| - This is a TurboRepo monorepo with pnpm workspaces | ||
| - Apps live in `apps/` (currently only tanstack-start) | ||
| - Shared packages live in `packages/` | ||
| - External services live in `services/` | ||
| - Use `turbo.json` for task definitions and caching | ||
|
|
||
| ## Environment & Configuration | ||
|
|
||
| - Use Zod for environment validation in TypeScript packages | ||
| - Follow the pattern in `packages/auth/env.ts` for type-safe env vars | ||
| - Never commit sensitive values; use `example.env` as a template | ||
| - Prefix AI service env vars with `AI_` to avoid conflicts | ||
|
|
||
| ## Authentication | ||
|
|
||
| - Use [WorkOS](https://workos.com/docs/llms.txt) for authentication and organization context. | ||
| - Do not invent custom auth flows. | ||
| - User identity and org context must be passed explicitly to services. | ||
|
|
||
| ## Frontend & UI | ||
|
|
||
| - All reusable UI components must live in the `packages/ui` package. use them | ||
| - Use Tailwind CSS for styling. | ||
| - Prefer shadcn/ui components where applicable. | ||
| - Do not create ad-hoc UI components in app folders. | ||
|
|
||
| ## Forms & State | ||
| - Here are the Tanstack [docs](https://tanstack.com/llms.txt) | ||
| - Use `@tanstack/react-form` for all forms. | ||
| - Use `@tanstack/react-query` for data fetching, caching, and mutations. | ||
| - Use `@tanstack/react-router` for routing. | ||
|
|
||
| ## APIs & Data Fetching | ||
|
|
||
| - Use tRPC for type-safe application API calls (user data, metrics, app state). | ||
| - Use @hey-api/openapi-ts to generate a typed client for the FastAPI AI service. | ||
| - Do not mix tRPC and OpenAPI clients. | ||
| - Do not have the AI service call the application API. | ||
|
|
||
| ## Database & Validation | ||
|
|
||
| - Use Drizzle ORM for database access. | ||
| - Use Zod for validation. | ||
| - Use `drizzle-zod` for deriving Zod schemas from Drizzle models. | ||
| - Do not duplicate schema definitions manually. | ||
| - Place non-database Zod schemas in the `packages/validators` package. | ||
|
|
||
| ## AI Service Integration | ||
|
|
||
| - The AI service receives all required inputs (user context, metrics, documents). | ||
| - The AI service must not fetch user or metrics data on its own. | ||
| - Inputs should be explicit, minimal, and versionable. | ||
| - AI service shouldn't have a seperate auth flow it should instead use the AI_SERVICE_KEY env var to authenticate requests from the main app which will have that variable sent using a secure header. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| - This is a PoC: prioritize developer speed and clarity over abstraction. | ||
| - Treat all backends as APIs; do not couple services together. | ||
| - The AI service is stateless and must not call application APIs directly. | ||
| - always use pnpm and pnpx for package management | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix grammar/capitalization in the guidance bullets. ✍️ Proposed edit-- always use pnpm and pnpx for package management
+- Always use pnpm and pnpx for package management.
-- All reusable UI components must live in the `packages/ui` package. use them
+- All reusable UI components must live in the `packages/ui` package. Use them.Also applies to: 31-31 🤖 Prompt for AI Agents |
||
|
|
||
| ## Monorepo Structure | ||
|
|
||
|
|
@@ -27,7 +28,7 @@ | |
|
|
||
| ## Frontend & UI | ||
|
|
||
| - All reusable UI components must live in the `packages/ui` package. | ||
| - All reusable UI components must live in the `packages/ui` package. use them | ||
| - Use Tailwind CSS for styling. | ||
| - Prefer shadcn/ui components where applicable. | ||
| - Do not create ad-hoc UI components in app folders. | ||
|
|
@@ -41,7 +42,7 @@ | |
| ## APIs & Data Fetching | ||
|
|
||
| - Use tRPC for type-safe application API calls (user data, metrics, app state). | ||
| - Use OpenAPI Generator to generate a typed client for the FastAPI AI service. | ||
| - Use @hey-api/openapi-ts to generate a typed client for the FastAPI AI service. | ||
| - Do not mix tRPC and OpenAPI clients. | ||
| - Do not have the AI service call the application API. | ||
|
|
||
|
|
||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||
| import { Link, useLocation } from "@tanstack/react-router"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export function NotFound() { | ||||||||||||||||||||||||||
| const location = useLocation(); | ||||||||||||||||||||||||||
| console.log("NotFound triggered for path:", location.pathname); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+1
to
+6
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove or gate the render-time console.log. Logging on every 404 render can spam production logs and expose path data. Consider gating to dev or removing. 🛠️ Suggested fix (gate to dev) export function NotFound() {
- const location = useLocation();
- console.log("NotFound triggered for path:", location.pathname);
+ const location = useLocation();
+ if (import.meta.env.DEV) {
+ console.log("NotFound triggered for path:", location.pathname);
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||
| <div className="flex flex-col items-center justify-center min-h-screen bg-background text-foreground p-4"> | ||||||||||||||||||||||||||
| <h1 className="text-9xl font-extrabold tracking-widest text-primary">404</h1> | ||||||||||||||||||||||||||
| <div className="bg-primary px-2 text-sm rounded rotate-12 absolute text-primary-foreground"> | ||||||||||||||||||||||||||
| Page Not Found | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| <div className="mt-8 text-center"> | ||||||||||||||||||||||||||
| <div className="text-xl font-medium mb-4"> | ||||||||||||||||||||||||||
| Oops! The page you asked for doesn't exist. | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| <Link | ||||||||||||||||||||||||||
| to="/" | ||||||||||||||||||||||||||
| className="px-6 py-3 rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors duration-200" | ||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||
| Go Home | ||||||||||||||||||||||||||
| </Link> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,44 @@ | ||
| import { useNavigate } from "@tanstack/react-router"; | ||
| import { useAuth } from "@workos/authkit-tanstack-react-start/client"; | ||
| import { getSignInUrl } from "@workos/authkit-tanstack-react-start"; | ||
| import { createServerFn } from "@tanstack/react-start"; | ||
|
|
||
| import { Button } from "@governance/ui/button"; | ||
|
|
||
| import { authClient } from "~/auth/client"; | ||
| const getSignInUrlFn = createServerFn({ method: "GET" }).handler(async () => { | ||
| return await getSignInUrl(); | ||
| }); | ||
|
|
||
| export function AuthShowcase() { | ||
| const { data: session } = authClient.useSession(); | ||
| const navigate = useNavigate(); | ||
| const { user, loading, signOut } = useAuth(); | ||
|
|
||
| if (!session) { | ||
| if (loading) { | ||
| return <div className="text-muted-foreground">Loading...</div>; | ||
| } | ||
|
|
||
| if (!user) { | ||
| return ( | ||
| <Button | ||
| size="lg" | ||
| onClick={async () => { | ||
| const res = await authClient.signIn.social({ | ||
| provider: "discord", | ||
| callbackURL: "/", | ||
| }); | ||
| if (!res.data?.url) { | ||
| throw new Error("No URL returned from signInSocial"); | ||
| } | ||
| await navigate({ href: res.data.url, replace: true }); | ||
| const signInUrl = await getSignInUrlFn(); | ||
| window.location.href = signInUrl; | ||
| }} | ||
| > | ||
| Sign in with Discord | ||
| Sign in with WorkOS | ||
| </Button> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <div className="flex flex-col items-center justify-center gap-4"> | ||
| <p className="text-center text-2xl"> | ||
| <span>Logged in as {session.user.name}</span> | ||
| <span> | ||
| Logged in as {user.firstName} {user.lastName} | ||
| </span> | ||
| </p> | ||
| <p className="text-muted-foreground">{user.email}</p> | ||
|
|
||
| <Button | ||
| size="lg" | ||
| onClick={async () => { | ||
| await authClient.signOut(); | ||
| await navigate({ href: "/", replace: true }); | ||
| }} | ||
| > | ||
| <Button size="lg" onClick={() => signOut()}> | ||
|
Comment on lines
+1
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -type f -name "auth-showcase.tsx" | head -20Repository: AFAskar/Governance-Agent Length of output: 121 🏁 Script executed: git ls-files | grep -E "(auth-showcase|authkit)" | head -30Repository: AFAskar/Governance-Agent Length of output: 119 🏁 Script executed: fd "auth-showcase" --type fRepository: AFAskar/Governance-Agent Length of output: 119 🏁 Script executed: cat -n ./apps/tanstack-start/src/component/auth-showcase.tsxRepository: AFAskar/Governance-Agent Length of output: 1569 🏁 Script executed: rg "@workos/authkit-tanstack-react-start" -t tsx -t ts --context 3 | head -80Repository: AFAskar/Governance-Agent Length of output: 95 🏁 Script executed: rg "getSignInUrl|signOut" -t tsx -t ts -A 2 -B 2 | head -100Repository: AFAskar/Governance-Agent Length of output: 95 🏁 Script executed: find . -type f -name "package.json" -path "*/tanstack-start/*" -o -name "package.json" -path "*/root" | head -5Repository: AFAskar/Governance-Agent Length of output: 102 🏁 Script executed: cat ./apps/tanstack-start/package.jsonRepository: AFAskar/Governance-Agent Length of output: 2028 🏁 Script executed: rg "getSignInUrl|signOut" --type-list | grep -i tsxRepository: AFAskar/Governance-Agent Length of output: 457 🏁 Script executed: rg "getSignInUrl|signOut" -A 3 -B 2 | head -150Repository: AFAskar/Governance-Agent Length of output: 2627 🏁 Script executed: rg "useAuth" --max-count 20 -B 3 -A 5Repository: AFAskar/Governance-Agent Length of output: 1273 🏁 Script executed: rg "try.*catch" apps/tanstack-start/src -B 2 -A 4 | head -80Repository: AFAskar/Governance-Agent Length of output: 50 🏁 Script executed: rg "getSignInUrlFn" -B 2 -A 5Repository: AFAskar/Governance-Agent Length of output: 1355 🏁 Script executed: rg "onClick.*async" apps/tanstack-start/src -B 2 -A 8 | head -100Repository: AFAskar/Governance-Agent Length of output: 872 🏁 Script executed: rg "\.catch\|try\s*{" apps/tanstack-start/src -B 3 -A 4Repository: AFAskar/Governance-Agent Length of output: 163 🏁 Script executed: find apps/tanstack-start/src -type f -name "*.ts" -o -name "*.tsx" | head -20Repository: AFAskar/Governance-Agent Length of output: 558 🏁 Script executed: rg "\.catch|catch\s*\(" apps/tanstack-start/src -B 2 -A 3Repository: AFAskar/Governance-Agent Length of output: 50 🏁 Script executed: cat apps/tanstack-start/src/routes/index.tsxRepository: AFAskar/Governance-Agent Length of output: 6966 🏁 Script executed: rg "useState" apps/tanstack-start/src --max-count 10 -B 2 -A 2Repository: AFAskar/Governance-Agent Length of output: 50 🏁 Script executed: grep -r "use client" apps/tanstack-start/src/component --include="*.tsx"Repository: AFAskar/Governance-Agent Length of output: 50 🏁 Script executed: rg "onError|try|catch" packages/auth/src --max-count 20 -B 2 -A 3Repository: AFAskar/Governance-Agent Length of output: 50 🏁 Script executed: cat apps/tanstack-start/src/component/auth-showcase.tsx | head -50Repository: AFAskar/Governance-Agent Length of output: 1247 🏁 Script executed: web_search
What does `@workos/authkit-tanstack-react-start` getSignInUrl() and signOut() return and can they throw errors?Repository: AFAskar/Governance-Agent Length of output: 313 🌐 Web query:
💡 Result: Where errors can happen (and how to handle them)1)
|
||
| Sign out | ||
| </Button> | ||
| </div> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "seperate" should be "separate".
📝 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents