Skip to content

Commit 9c842aa

Browse files
committed
feat: workos support
1 parent 3db4d6a commit 9c842aa

File tree

10 files changed

+256
-1
lines changed

10 files changed

+256
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Setting up WorkOS
2+
3+
- Set the `VITE_WORKOS_CLIENT_ID` in your `.env.local`.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
VITE_WORKOS_CLIENT_ID=
2+
3+
# This should be your Custom Authentication Domain in production
4+
VITE_WORKOS_API_HOSTNAME=api.workos.com
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useAuth } from '@workos-inc/authkit-react'
2+
3+
export default function SignInButton({ large }: { large?: boolean }) {
4+
const { user, isLoading, signIn, signOut } = useAuth()
5+
6+
const buttonClasses = `${
7+
large ? 'px-6 py-3 text-base' : 'px-4 py-2 text-sm'
8+
} bg-blue-600 hover:bg-blue-700 text-white font-medium rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed`
9+
10+
if (user) {
11+
return (
12+
<div className="flex flex-col gap-3">
13+
<div className="flex items-center gap-2">
14+
{user.profilePictureUrl && (
15+
<img
16+
src={user.profilePictureUrl}
17+
alt={`Avatar of ${user.firstName} ${user.lastName}`}
18+
className="w-10 h-10 rounded-full"
19+
/>
20+
)}
21+
{user.firstName} {user.lastName}
22+
</div>
23+
<button onClick={() => signOut()} className={buttonClasses}>
24+
Sign Out
25+
</button>
26+
</div>
27+
)
28+
}
29+
30+
return (
31+
<button
32+
onClick={() => {
33+
signIn()
34+
}}
35+
className={buttonClasses}
36+
disabled={isLoading}
37+
>
38+
Sign In {large && 'with AuthKit'}
39+
</button>
40+
)
41+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useEffect } from "react";
2+
import { useAuth } from "@workos-inc/authkit-react";
3+
import { useLocation } from "@tanstack/react-router";
4+
5+
type UserOrNull = ReturnType<typeof useAuth>["user"];
6+
7+
// redirects to the sign-in page if the user is not signed in
8+
export const useUser = (): UserOrNull => {
9+
const { user, isLoading, signIn } = useAuth();
10+
const location = useLocation();
11+
12+
useEffect(() => {
13+
if (!isLoading && !user) {
14+
signIn({
15+
state: { returnTo: location.pathname },
16+
});
17+
} else {
18+
console.log(user);
19+
}
20+
}, [isLoading, user]);
21+
22+
return user;
23+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { AuthKitProvider } from '@workos-inc/authkit-react'
2+
import { useNavigate } from '@tanstack/react-router'
3+
4+
const VITE_WORKOS_CLIENT_ID = import.meta.env.VITE_WORKOS_CLIENT_ID
5+
if (!VITE_WORKOS_CLIENT_ID) {
6+
throw new Error('Add your WorkOS Client ID to the .env.local file')
7+
}
8+
9+
const VITE_WORKOS_API_HOSTNAME = import.meta.env.VITE_WORKOS_API_HOSTNAME
10+
if (!VITE_WORKOS_API_HOSTNAME) {
11+
throw new Error('Add your WorkOS API Hostname to the .env.local file')
12+
}
13+
14+
export default function AppWorkOSProvider({
15+
children,
16+
}: {
17+
children: React.ReactNode
18+
}) {
19+
const navigate = useNavigate()
20+
21+
return (
22+
<AuthKitProvider
23+
clientId={VITE_WORKOS_CLIENT_ID}
24+
apiHostname={VITE_WORKOS_API_HOSTNAME}
25+
onRedirectCallback={({ state }) => {
26+
if (state?.returnTo) {
27+
navigate(state.returnTo)
28+
}
29+
}}
30+
>
31+
{children}
32+
</AuthKitProvider>
33+
)
34+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
import { useAuth } from '@workos-inc/authkit-react'
3+
4+
export const Route = createFileRoute('/demo/workos')({
5+
ssr: false,
6+
component: App,
7+
})
8+
9+
function App() {
10+
const { user, isLoading, signIn, signOut } = useAuth()
11+
12+
if (isLoading) {
13+
return (
14+
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 flex items-center justify-center p-4">
15+
<div className="bg-gray-800/50 backdrop-blur-sm rounded-2xl shadow-2xl p-8 w-full max-w-md border border-gray-700/50">
16+
<p className="text-gray-400 text-center">Loading...</p>
17+
</div>
18+
</div>
19+
)
20+
}
21+
22+
if (user) {
23+
return (
24+
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 flex items-center justify-center p-4">
25+
<div className="bg-gray-800/50 backdrop-blur-sm rounded-2xl shadow-2xl p-8 w-full max-w-md border border-gray-700/50">
26+
<h1 className="text-2xl font-bold text-white mb-6 text-center">
27+
User Profile
28+
</h1>
29+
30+
<div className="space-y-6">
31+
{/* Profile Picture */}
32+
{user.profilePictureUrl && (
33+
<div className="flex justify-center">
34+
<img
35+
src={user.profilePictureUrl}
36+
alt={`Avatar of ${user.firstName} ${user.lastName}`}
37+
className="w-24 h-24 rounded-full border-4 border-gray-700 shadow-lg"
38+
/>
39+
</div>
40+
)}
41+
42+
{/* User Information */}
43+
<div className="space-y-4">
44+
<div className="bg-gray-700/30 rounded-lg p-4 border border-gray-600/30">
45+
<label className="text-gray-400 text-sm font-medium block mb-1">
46+
First Name
47+
</label>
48+
<p className="text-white text-lg">{user.firstName || 'N/A'}</p>
49+
</div>
50+
51+
<div className="bg-gray-700/30 rounded-lg p-4 border border-gray-600/30">
52+
<label className="text-gray-400 text-sm font-medium block mb-1">
53+
Last Name
54+
</label>
55+
<p className="text-white text-lg">{user.lastName || 'N/A'}</p>
56+
</div>
57+
58+
<div className="bg-gray-700/30 rounded-lg p-4 border border-gray-600/30">
59+
<label className="text-gray-400 text-sm font-medium block mb-1">
60+
Email
61+
</label>
62+
<p className="text-white text-lg break-all">
63+
{user.email || 'N/A'}
64+
</p>
65+
</div>
66+
67+
<div className="bg-gray-700/30 rounded-lg p-4 border border-gray-600/30">
68+
<label className="text-gray-400 text-sm font-medium block mb-1">
69+
User ID
70+
</label>
71+
<p className="text-gray-300 text-sm font-mono break-all">
72+
{user.id || 'N/A'}
73+
</p>
74+
</div>
75+
</div>
76+
77+
{/* Sign Out Button */}
78+
<button
79+
onClick={() => signOut()}
80+
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-6 rounded-lg transition-colors shadow-lg hover:shadow-xl"
81+
>
82+
Sign Out
83+
</button>
84+
</div>
85+
</div>
86+
</div>
87+
)
88+
}
89+
90+
return (
91+
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 flex items-center justify-center p-4">
92+
<div className="bg-gray-800/50 backdrop-blur-sm rounded-2xl shadow-2xl p-8 w-full max-w-md border border-gray-700/50">
93+
<h1 className="text-2xl font-bold text-white mb-6 text-center">
94+
WorkOS Authentication
95+
</h1>
96+
<p className="text-gray-400 text-center mb-6">
97+
Sign in to view your profile information
98+
</p>
99+
<button
100+
onClick={() => signIn()}
101+
disabled={isLoading}
102+
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-6 rounded-lg transition-colors shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed"
103+
>
104+
Sign In with AuthKit
105+
</button>
106+
</div>
107+
</div>
108+
)
109+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "WorkOS",
3+
"description": "Add WorkOS authentication to your application.",
4+
"phase": "add-on",
5+
"modes": ["file-router"],
6+
"type": "add-on",
7+
"link": "https://workos.com",
8+
"tailwind": true,
9+
"routes": [
10+
{
11+
"icon": "CircleUserRound",
12+
"url": "/demo/workos",
13+
"name": "WorkOS",
14+
"path": "src/routes/demo.workos.tsx",
15+
"jsName": "WorkOSDemo"
16+
}
17+
],
18+
"integrations": [
19+
{
20+
"type": "header-user",
21+
"jsName": "WorkOSHeader",
22+
"path": "src/components/workos-user.tsx"
23+
},
24+
{
25+
"type": "provider",
26+
"jsName": "WorkOSProvider",
27+
"path": "src/integrations/workos/provider.tsx"
28+
}
29+
]
30+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"dependencies": {
3+
"@workos-inc/authkit-react": "^0.13.0",
4+
"zod": "^4.1.11"
5+
}
6+
}
Lines changed: 5 additions & 0 deletions
Loading

packages/cta-engine/src/create-app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ Use the following commands to start your app:
234234
getPackageManagerScriptCommand(options.packageManager, ['dev']),
235235
)}
236236
237-
Please check the README.md for information on testing, styling, adding routes, etc.${errorStatement}`,
237+
Please read the README.md for information on testing, styling, adding routes, etc.${errorStatement}`,
238238
)
239239
}
240240

0 commit comments

Comments
 (0)