Skip to content
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

🐛 Fix auth b2c #323

Merged
merged 1 commit into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/client-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
"@stytch/nextjs": "^18.0.0",
"@stytch/vanilla-js": "^4.7.1",
"@tanstack/react-query": "^5.12.2",
"@tanstack/react-query-devtools": "^5.25.0",
"@tanstack/react-query-next-experimental": "^5.25.0",
"@tanstack/react-table": "^8.11.8",
"antd": "^5.11.5",
"api": "workspace:*",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^0.2.1",
Expand All @@ -50,8 +53,7 @@
"tailwind-merge": "^2.2.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.22.4",
"zustand": "^4.4.7",
"api": "workspace:*"
"zustand": "^4.4.7"
},
"devDependencies": {
"@types/cookies": "^0.9.0",
Expand Down
63 changes: 63 additions & 0 deletions apps/client-ts/src/app/authenticate/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client";

import { Suspense, useEffect } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useStytchUser, useStytch } from "@stytch/nextjs";

const OAUTH_TOKEN = "oauth";
const MAGIC_LINKS_TOKEN = "magic_links";

/**
* During both the Magic link and OAuth flows, Stytch will redirect the user back to your application to a specified redirect URL (see Login.tsx).
* Stytch will append query parameters to the redirect URL which are then used to complete the authentication flow.
* A redirect URL for this example app will look something like: http://localhost:3000/authenticate?stytch_token_type=magic_links&token=abc123
*
* The AuthenticatePage will detect the presence of a token in the query parameters, and attempt to authenticate it.
*
* On successful authentication, a session will be created and the user will be redirect to /profile.
*/
const InnerAuthenticate = () => {
const { user, isInitialized } = useStytchUser();
const stytch = useStytch();
const router = useRouter();
const searchParams = useSearchParams();

useEffect(() => {
if (stytch && !user && isInitialized) {
const token = searchParams.get("token");
const stytch_token_type = searchParams.get("stytch_token_type");

if (token && stytch_token_type === OAUTH_TOKEN) {
stytch.oauth.authenticate(token, {
session_duration_minutes: 60,
});
} else if (token && stytch_token_type === MAGIC_LINKS_TOKEN) {
stytch.magicLinks.authenticate(token, {
session_duration_minutes: 60,
});
}
}
Comment on lines +25 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the authentication process with Stytch SDK to manage failed authentication attempts gracefully. This could involve redirecting the user to an error page or displaying an error message.

}, [isInitialized, router, searchParams, stytch, user]);

useEffect(() => {
if (!isInitialized) {
return;
}
if (user) {
router.replace("/b2c/profile");
}
}, [router, user, isInitialized]);

return null;
};

const Authenticate = () => {

return (
<Suspense>
<InnerAuthenticate/>
</Suspense>
Comment on lines +57 to +59
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a fallback component to the Suspense wrapper to improve the user experience during loading or if an error occurs during the asynchronous operations within InnerAuthenticate.

)
}

export default Authenticate;
17 changes: 17 additions & 0 deletions apps/client-ts/src/app/b2c/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use client';

import LoginWithStytchSDKUI from "@/components/Auth/b2c/LoginWithStytchSDKUI";

export default async function Page() {
return (
<div className='min-h-screen grid lg:grid-cols-2 mx-auto text-left'>
<div className='flex-1 flex flex-col justify-center py-12 px-4 sm:px-6 lg:flex-none lg:px-20 xl:px-24'>
<img src="/logo.png" className='w-14' />
<LoginWithStytchSDKUI />
</div>
<div className='hidden lg:block relative flex-1'>
<img className='absolute inset-0 h-full w-full object-cover border-l' src="/bgbg.jpeg" alt='Login Page Image' />
</div>
</div>
)
}
16 changes: 16 additions & 0 deletions apps/client-ts/src/app/b2c/profile/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import "./../../globals.css";
import { RootLayout } from "@/components/RootLayout";


export default function Layout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<>
<RootLayout/>
{children}
</>
);
}
60 changes: 60 additions & 0 deletions apps/client-ts/src/app/b2c/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client'

import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator"
import { useRouter } from "next/navigation";
import { useStytch, useStytchSession, useStytchUser } from "@stytch/nextjs";

const Profile = () => {
const stytch = useStytch();
// Get the Stytch User object if available
const { user } = useStytchUser();
// Get the Stytch Session object if available
const { session } = useStytchSession();
const router = useRouter();

return (
<div className="ml-[200px] p-10">
<Card>
<CardHeader>
<CardTitle>Profile</CardTitle>
<CardDescription>
<div className="flex items-center">
{user?.name.first_name} {user?.name.last_name}
</div>
</CardDescription>
</CardHeader>
<CardContent>
<h4 className="text-sm font-medium mb-2">Connected user</h4>

<div className="flex space-x-2">
<Input value={`${user?.emails[0].email}`} readOnly />
<Button variant="secondary" className="shrink-0">
Copy
</Button>
</div>
<Separator className="my-4" />
<div className="pt-4">
<Button onClick={() => {
stytch.session.revoke()
router.push('/b2c/login');
}}>
Log Out
</Button>
</div>
</CardContent>
</Card>
</div>
);
};


export default Profile;
51 changes: 51 additions & 0 deletions apps/client-ts/src/components/Auth/b2c/LoginWithStytchSDKUI.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use client';

import { StytchLogin } from '@stytch/nextjs';
import { StytchLoginConfig, OAuthProviders, Products, StyleConfig, StytchEvent, StytchError } from '@stytch/vanilla-js';
import { getDomainFromWindow } from '@/lib/stytch/urlUtils';

const sdkStyle: StyleConfig = {
fontFamily: '"Helvetica New", Helvetica, sans-serif',
buttons: {
primary: {
backgroundColor: '#19303d',
textColor: '#ffffff',
},
},
};

const sdkConfig: StytchLoginConfig = {
products: [Products.oauth, Products.emailMagicLinks],
emailMagicLinksOptions: {
loginRedirectURL: getDomainFromWindow() + '/authenticate',
loginExpirationMinutes: 30,
signupRedirectURL: getDomainFromWindow() + '/authenticate',
signupExpirationMinutes: 30,
createUserAsPending: false,
},
oauthOptions: {
providers: [
{ type: OAuthProviders.Google },
{ type: OAuthProviders.Apple },
{ type: OAuthProviders.Microsoft },
{ type: OAuthProviders.Facebook },
{ type: OAuthProviders.Github },
{ type: OAuthProviders.GitLab },
],
loginRedirectURL: getDomainFromWindow() + '/authenticate',
signupRedirectURL: getDomainFromWindow() + '/authenticate',
},
};

const callbackConfig = {
onEvent: (message: StytchEvent) => console.log(message),
onError: (error: StytchError) => console.log(error),
}

const LoginWithStytchSDKUI = () => {
return (
<StytchLogin config={sdkConfig} styles={sdkStyle} callbacks={callbackConfig} />
)
}

export default LoginWithStytchSDKUI;
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const AddLinkedAccount = () => {

const posthog = usePostHog()

const {idOrg} = useOrganisationStore();
//const {idOrg} = useOrganisationStore();
const {idProject} = useProjectStore();


Expand All @@ -86,7 +86,7 @@ const AddLinkedAccount = () => {
console.log(values)
mutate({
linked_user_origin_id: values.linkedUserIdentifier,
alias: idOrg,
alias: "", //TODO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to use an empty string for the alias value in the mutate function call includes a TODO comment. Consider adding a more descriptive TODO comment or implementing the intended logic to avoid confusion or unintended behavior in the future.

id_project: idProject
});
setShowNewLinkedUserDialog({open: false})
Expand Down
7 changes: 6 additions & 1 deletion apps/client-ts/src/components/Provider/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ import React, { useState } from "react"
import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental"
import { QueryClientProvider, QueryClient } from "@tanstack/react-query"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import { StytchProvider } from "@stytch/nextjs"
import { createStytchUIClient } from '@stytch/nextjs/ui';

function Provider({ children }: any) {
const client = new QueryClient();
const stytch = createStytchUIClient(process.env.NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN || '');

return (
<>
<QueryClientProvider client={client}>
<ReactQueryStreamedHydration>
{children}
<StytchProvider stytch={stytch}>
{children}
</StytchProvider>
</ReactQueryStreamedHydration>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
Expand Down
Loading
Loading