T
TanStack13mo ago
frozen-sapphire

How is this auth implementation (WorkOS/Syncing to DB)

I have a question for my auth use case if anyone is willing to offer a 2nd opinion In my app an Organization has both 1+ users and Org/Users are assigned to 1+ workspaces. Using WorkOS here and trying to make sure my backend is synced with WorkOS Not sure if there's a better way of doing this. Root Route context
export type AuthState = {
user: User
organizations: SelectOrganization[] | undefined
workspaces: SelectWorkspace[] | undefined
}
type RouterContext = {
queryClient: QueryClient
workOsAuth: ReturnType<typeof useAuth>
authState: AuthState
}
export type AuthState = {
user: User
organizations: SelectOrganization[] | undefined
workspaces: SelectWorkspace[] | undefined
}
type RouterContext = {
queryClient: QueryClient
workOsAuth: ReturnType<typeof useAuth>
authState: AuthState
}
Root Route beforeLoad check WorkOS user exists, if not return and let _auth handle redirecting to login (to avoid infinite loops). Query backend for user, organization and workspaces. a) If !user, then backend out of sync, need to useMutation in root component to sync (you can't use ts query mutation in the beforeload/loader I assume? b) return auth state with queried user, orgs, workspaces (if available) so context is filled with these values
6 Replies
frozen-sapphire
frozen-sapphireOP13mo ago
_auth/route.tsx beforeLoad
const { workOsAuth, authState } = context
if (!workOsAuth.user) {
// If WorkOS user doesn't exist, redirect to login
return redirect({ to: '/login' })
}

// If no WorkOS org and no database org, redirect to onboarding
if (!workOsAuth.organizationId && !authState?.organizations?.length) {
return redirect({ to: '/onboarding/organization' })
}

// If WorkOS org & database org exist, but no workspaces, redirect to workspace onboarding step
if (
workOsAuth.organizationId &&
authState?.organizations &&
authState.organizations.length > 0 &&
(!authState?.workspaces || authState.workspaces.length === 0)
) {
return redirect({ to: '/onboarding/workspace' })
}

// Make sure user has completed onboarding profile
if (authState?.user.onboardingComplete === false) {
return redirect({ to: '/onboarding/profile' })
}
const { workOsAuth, authState } = context
if (!workOsAuth.user) {
// If WorkOS user doesn't exist, redirect to login
return redirect({ to: '/login' })
}

// If no WorkOS org and no database org, redirect to onboarding
if (!workOsAuth.organizationId && !authState?.organizations?.length) {
return redirect({ to: '/onboarding/organization' })
}

// If WorkOS org & database org exist, but no workspaces, redirect to workspace onboarding step
if (
workOsAuth.organizationId &&
authState?.organizations &&
authState.organizations.length > 0 &&
(!authState?.workspaces || authState.workspaces.length === 0)
) {
return redirect({ to: '/onboarding/workspace' })
}

// Make sure user has completed onboarding profile
if (authState?.user.onboardingComplete === false) {
return redirect({ to: '/onboarding/profile' })
}
.
└── routes/
├── _auth/
│ ├── route.tsx (layout)
│ ├── (dashboard)/
│ │ ├── a.tsx
│ │ └── b.tsx
│ └── _onboarding/
│ ├── route.tsx (layout)
│ └── onboarding/
│ ├── organization
│ ├── workspace
│ └── profile
├── login
└── logout
.
└── routes/
├── _auth/
│ ├── route.tsx (layout)
│ ├── (dashboard)/
│ │ ├── a.tsx
│ │ └── b.tsx
│ └── _onboarding/
│ ├── route.tsx (layout)
│ └── onboarding/
│ ├── organization
│ ├── workspace
│ └── profile
├── login
└── logout
I was thinking maybe I should have two auth layouts, one for pre-onboarding and one post-onboarding (where org and workspaces have been created), but not sure
like-gold
like-gold9mo ago
howdy @DiamondDragon - curious how your approach has worked out. i'm thinking about leveraging the (relatively new) authkitprovider from workos
frozen-sapphire
frozen-sapphireOP9mo ago
My use case specifically needed to have a lot of organizations for users, so thats why i opted for WorkOS vs something like Clerk since it charges a lot for orgs (not sure if thats changed recently) Ultimately the way i understand doing auth with TSR is that you have to just think about where you check the auth state and where to redirect if isAuthenticated = true or false. I've landed on a _auth and _public directory to make it clear
like-gold
like-gold9mo ago
yeah, we have a very complex use case too: multiple orgs, sharing across orgs, multiple workspaces within orgs. tough nailing it down right. you just using workos SDK or the authkit provider? curious what your main.tsx and __root.tsx look like and what an example of your beforeLoad looks like I'm getting typescript errors in my _auth.tsx
frozen-sapphire
frozen-sapphireOP9mo ago
I’d have to go back and check I ended up just ignoring auth and commenting it out so I focus on building the app, which means I sort of have to backtrack and then add the org and workspace features. I did however get it working using both the authkit provider and the sdk.. not sure if 100% correct tho lol If you I’m happy to ideate , maybe we build a simple sample app with workos where you can login as a user, belong to diff orgs, each which can have workspaces. @outofgamut
like-gold
like-gold9mo ago
down to talk more through DM

Did you find this page helpful?