Update auth-with-stytch example to link to the official guide (#62770)

## What?

This example was outdated and using deprecated libraries, also failing
with Turbopack because it used edge-cases in webpack to function. I've
removed the example code and left a link to their official documentation
which I'm assuming is maintained.

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->


Closes NEXT-2670
This commit is contained in:
Tim Neutkens 2024-03-04 13:53:58 +01:00 committed by GitHub
parent 330b04ff55
commit dd98e7740d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 3 additions and 1223 deletions

View file

@ -1,8 +0,0 @@
# The two iron-session values may be left as-is while testing out this example app.
IRON_SESSION_COOKIE_NAME="stytch_next_example_cookie"
IRON_SESSION_PASSWORD="complex_password_at_least_32_characters_long"
# The below values may be found in your Stytch Dashboard: https://stytch.com/dashboard/api-keys
STYTCH_PROJECT_ENV=test
STYTCH_PROJECT_ID="YOUR_STYTCH_PROJECT_ID"
STYTCH_SECRET="YOUR_STYTCH_SECRET"
NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN="YOUR_STYTCH_PUBLIC_TOKEN"

View file

@ -1,68 +0,0 @@
# Stytch + Next.js example app on Vercel
This is a [Stytch](https://stytch.com) + [Next.js](https://nextjs.org/) project that showcases how to enable elegant authentication in your application.
<p align="center"><img src="./public/example-app-image.png" alt="stytch" width="50%"/></p>
In this repo, we have two sample auth flows:
- SDK integration: This flow uses Stytch's React component to create a login and sign-up flow using [Email Magic Links](https://stytch.com/docs/api/send-by-email).
- API integration: This flow uses a custom UI with Stytch's backend API for [Onetime Passcodes(OTP) via SMS](https://stytch.com/docs/api/sms-otp-overview) authentication.
Both flows use Stytch's [Node client library](https://github.com/stytchauth/stytch-node) and [`iron-session`](https://github.com/vvo/next-iron-session) for session management.
**Note:** By default this example app enables three of our OAuth providers, Google, Microsoft, and Apple. If you haven't set up these OAuth providers in your [Dashboard](https://stytch.com/dashboard/oauth), you'll receive a redirect error when you attempt to login via those providers. You may remove all OAuth methods by removing `SDKProductTypes.oauth` from the `products` array in [pages/index.tsx](pages/index.tsx) or adjust which ones are displayed by via `oauthOptions.providers` in the same file. More detail on working with OAuth providers in our SDK may be found in our [Docs](https://stytch.com/docs/javascript-sdk#javascript-sdk/oauth).
# Deploy on Vercel
## Setting up Stytch
The first step is to configure the appropriate redirect URLs for your project. You'll set these magic link redirect URLs in the [Redirect URLs](https://stytch.com/dashboard/redirect-urls) section of your Dashboard. Add `https://*.vercel.app:3000` as both a login and sign-up redirect URL.
## Running the example app
Now just click the deploy button below! Once you're signed in to your Vercel account, you'll be guided through how to get up and running quickly. Check out [.env.template](.env.template) for pointers on filling in the appropriate environment variables for this step.
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Fblob%2Fcanary%2Fexamples%2Fauth-with-stytch%2F&env=STYTCH_PROJECT_ENV,STYTCH_PROJECT_ID,STYTCH_SECRET,NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN,IRON_SESSION_PASSWORD,IRON_SESSION_COOKIE_NAME&envDescription=All%20variables%20here%20need%20values%2C%20see%20the%20following%20link%20for%20pointers%20on%20how%20to%20feel%20these%20out.&envLink=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Fblob%2Fcanary%2Fexamples%2Fauth-with-stytch%2F.env.template&project-name=stytch-nextjs-vercel&repo-name=stytch-nextjs-vercel&demo-title=Stytch%20on%20Next.js%20with%20Vercel&demo-description=Next.js%20example%20app%20using%20Stytch%20authentication&demo-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Fblob%2Fcanary%2Fexamples%2Fauth-with-stytch&demo-image=https%3A%2F%2Fstytch.com%2Flogo-preview.png)
# Running locally via `vercel dev`
## Setting up Stytch
After signing up for Stytch, you'll need your Project's `project_id`, `secret`, and `public_token`. You can find these in the [API keys tab](https://stytch.com/dashboard/api-keys).
Once you've gathered these values, add them to a new .env.local file.
Example:
```bash
cp .env.template .env.local
# Replace your keys in new .env.local file
```
Next we'll configure the appropriate redirect URLs for your project, you'll set these magic link URLs for your project in the [Redirect URLs](https://stytch.com/dashboard/redirect-urls) section of your Dashboard. Add `http://localhost:3000/api/authenticate_magic_link` as both a login and sign-up redirect URL.
## Running the example app
Install dependencies by running
```bash
npm install
# or
yarn install
```
You can then run a development server using:
```bash
vercel dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
## Documentation
Learn more about some of Stytch's products used in this example app:
- [Stytch React](https://www.npmjs.com/package/@stytch/stytch-react)
- [Stytch's node client library](https://www.npmjs.com/package/stytch)
- [iron-session](https://github.com/vvo/next-iron-session)

View file

@ -1,35 +0,0 @@
import React from "react";
import styles from "../styles/Home.module.css";
import { LoginMethod } from "../lib/types";
import StytchContainer from "./StytchContainer";
type Props = {
setLoginMethod: (loginMethod: LoginMethod) => void;
};
const LoginEntryPoint = (props: Props) => {
const { setLoginMethod } = props;
return (
<StytchContainer>
<h2>Hello Vercel!</h2>
<p className={styles.entrySubHeader}>
This example app demonstrates how you can integrate with Stytch using
Next.js and deploy on Vercel. Now, lets get started!
</p>
<button
className={styles.entryButton}
onClick={() => setLoginMethod(LoginMethod.SDK)}
>
SDK Integration (Email magic links)
</button>
<button
className={styles.entryButton}
onClick={() => setLoginMethod(LoginMethod.API)}
>
API Integration (SMS Passcodes)
</button>
</StytchContainer>
);
};
export default LoginEntryPoint;

View file

@ -1,27 +0,0 @@
import React, { useState } from "react";
import SendOTPForm from "./SendOTPForm";
import VerifyOTPForm from "./VerifyOTPForm";
import StytchContainer from "./StytchContainer";
const LoginWithSMS = () => {
const [otpSent, setOTPSent] = useState(false);
const [phoneNumber, setPhoneNumber] = useState("");
const [methodId, setMethodId] = useState("");
return (
<StytchContainer>
{!otpSent ? (
<SendOTPForm
phoneNumber={phoneNumber}
setMethodId={setMethodId}
setOTPSent={setOTPSent}
setPhoneNumber={setPhoneNumber}
/>
) : (
<VerifyOTPForm methodId={methodId} phoneNumber={phoneNumber} />
)}
</StytchContainer>
);
};
export default LoginWithSMS;

View file

@ -1,83 +0,0 @@
import React from "react";
import { sendOTP } from "../lib/otpUtils";
import styles from "../styles/Home.module.css";
type Props = {
phoneNumber: string;
setMethodId: (methodId: string) => void;
setOTPSent: (submitted: boolean) => void;
setPhoneNumber: (phoneNumber: string) => void;
};
const SendOTPForm = (props: Props): JSX.Element => {
const { phoneNumber, setMethodId, setOTPSent, setPhoneNumber } = props;
const [isDisabled, setIsDisabled] = React.useState(true);
const isValidNumber = (phoneNumberValue: string) => {
// Regex validates phone numbers in (xxx)xxx-xxxx, xxx-xxx-xxxx, xxxxxxxxxx, and xxx.xxx.xxxx format
const regex = /^[(]?[0-9]{3}[)]?[-s.]?[0-9]{3}[-s.]?[0-9]{4}$/g;
if (phoneNumberValue.match(regex)) {
return true;
}
return false;
};
const onPhoneNumberChange = (e: React.ChangeEvent<{ value: string }>) => {
setPhoneNumber(e.target.value);
if (isValidNumber(e.target.value)) {
setIsDisabled(false);
} else {
setIsDisabled(true);
}
};
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (isValidNumber(phoneNumber)) {
const methodId = await sendOTP(phoneNumber);
setMethodId(methodId);
setOTPSent(true);
}
};
return (
<div>
<h2>Enter phone number</h2>
<p className={styles.smsInstructions}>
Enter your phone number to receive a passcode for authentication.
</p>
<form onSubmit={onSubmit}>
<div className={styles.telInput}>
<input
className={styles.flag}
name="intlCode"
type="text"
value="+1"
readOnly
/>
<input
id={styles.phoneNumber}
className={styles.phoneNumber}
placeholder="(123) 456-7890"
value={phoneNumber}
onChange={onPhoneNumberChange}
type="tel"
/>
</div>
<p className={styles.smsDisclaimer}>
By continuing, you consent to receive an SMS for verification. Message
and data rates may apply.
</p>
<input
className={styles.primaryButton}
disabled={isDisabled}
id="button"
type="submit"
value="Continue"
/>
</form>
</div>
);
};
export default SendOTPForm;

View file

@ -1,20 +0,0 @@
import React from "react";
import styles from "../styles/Home.module.css";
import Image from "next/image";
import lockup from "/public/powered-by-stytch.svg";
type Props = {
children: React.ReactElement | React.ReactElement[];
};
const StytchContainer = (props: Props) => {
const { children } = props;
return (
<div className={styles.container}>
<div>{children}</div>
<Image alt="Powered by Stytch" height={15} src={lockup} width={150} />
</div>
);
};
export default StytchContainer;

View file

@ -1,168 +0,0 @@
import React from "react";
import styles from "../styles/Home.module.css";
import { sendOTP } from "../lib/otpUtils";
import { useRouter } from "next/router";
// Handles auto-tabbing to next passcode digit input.
// Logic inspired from https://stackoverflow.com/questions/15595652/focus-next-input-once-reaching-maxlength-value.
const autoTab = (target: HTMLInputElement, key?: string) => {
if (target.value.length >= target.maxLength) {
let next = target;
while ((next = next.nextElementSibling as HTMLInputElement)) {
if (next == null) break;
if (next.tagName.toLowerCase() === "input") {
next?.focus();
break;
}
}
}
// Move to previous field if empty (user pressed backspace)
else if (target.value.length === 0) {
let previous = target;
while ((previous = previous.previousElementSibling as HTMLInputElement)) {
if (previous == null) break;
if (previous.tagName.toLowerCase() === "input") {
previous.focus();
break;
}
}
}
};
type Props = {
methodId: string;
phoneNumber: string;
};
const VerifyOTPForm = (props: Props) => {
const { methodId, phoneNumber } = props;
const [isDisabled, setIsDisabled] = React.useState(true);
const [currentMethodId, setCurrentMethodId] = React.useState(methodId);
const [isError, setIsError] = React.useState(false);
const router = useRouter();
const strippedNumber = phoneNumber.replace(/\D/g, "");
const parsedPhoneNumber = `(${strippedNumber.slice(
0,
3,
)}) ${strippedNumber.slice(3, 6)}-${strippedNumber.slice(6, 10)}`;
const isValidPasscode = () => {
const regex = /^[0-9]$/g;
const inputs = document.getElementsByClassName(styles.passcodeInput);
for (let i = 0; i < inputs.length; i++) {
if (!(inputs[i] as HTMLInputElement).value.match(regex)) {
return false;
}
}
return true;
};
const onPasscodeDigitChange = () => {
if (isValidPasscode()) {
setIsDisabled(false);
setIsError(false);
} else {
setIsDisabled(true);
}
};
const resetPasscode = () => {
const inputs = document.getElementsByClassName(styles.passcodeInput);
for (let i = 0; i < inputs.length; i++) {
(inputs[i] as HTMLInputElement).value = "";
}
document.getElementById("digit-0")?.focus();
setIsDisabled(true);
};
const resendCode = async () => {
const methodId = await sendOTP(phoneNumber);
setCurrentMethodId(methodId);
resetPasscode();
setIsError(false);
};
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (isValidPasscode()) {
let otpInput = "";
const inputs = document.getElementsByClassName(styles.passcodeInput);
for (let i = 0; i < inputs.length; i++) {
otpInput += (inputs[i] as HTMLInputElement).value;
}
const resp = await fetch("/api/authenticate_otp", {
method: "POST",
body: JSON.stringify({ otpInput, methodId: currentMethodId }),
});
if (resp.status === 200) {
router.push("/profile");
} else {
setIsError(true);
resetPasscode();
}
}
};
const renderPasscodeInputs = () => {
const inputs = [];
for (let i = 0; i < 6; i += 1) {
inputs.push(
<input
autoFocus={i === 0}
className={styles.passcodeInput}
id={`digit-${i}`}
key={i}
maxLength={1}
onChange={onPasscodeDigitChange}
onKeyUp={(e) => autoTab(e.target as HTMLInputElement, e.key)}
placeholder="0"
size={1}
type="text"
/>,
);
}
return inputs;
};
return (
<div>
<h2>Enter passcode</h2>
<p className={styles.smsInstructions}>
A 6-digit passcode was sent to you at{" "}
<strong>{parsedPhoneNumber}</strong>.
</p>
<form onSubmit={onSubmit}>
<div className={styles.passcodeContainer}>
<p className={styles.errorText}>
{isError ? "Invalid code. Please try again." : ""}
</p>
<div className={styles.passcodeInputContainer}>
{renderPasscodeInputs()}
</div>
</div>
<div className={styles.resendCodeContainer}>
<p className={styles.resendCodeText}>Didnt get it? </p>
<button
className={`${styles.resendCodeButton} ${styles.resendCodeText}`}
onClick={resendCode}
type="button"
>
Resend code
</button>
</div>
<input
className={styles.primaryButton}
disabled={isDisabled}
id="button"
type="submit"
value="Continue"
/>
</form>
</div>
);
};
export default VerifyOTPForm;

View file

@ -1,19 +0,0 @@
import * as stytch from "stytch";
let client: stytch.Client;
const loadStytch = () => {
if (!client) {
client = new stytch.Client({
project_id: process.env.STYTCH_PROJECT_ID || "",
secret: process.env.STYTCH_SECRET || "",
env:
process.env.STYTCH_PROJECT_ENV === "live"
? stytch.envs.live
: stytch.envs.test,
});
}
return client;
};
export default loadStytch;

View file

@ -1,11 +0,0 @@
export async function sendOTP(phoneNumber: string) {
const resp = await fetch("/api/send_otp", {
method: "POST",
body: JSON.stringify({
intlCode: "+1",
phoneNumber,
}),
});
const data = await resp.json();
return data.methodId;
}

View file

@ -1,4 +0,0 @@
export enum LoginMethod {
API,
SDK,
}

View file

@ -1,28 +0,0 @@
import { NextApiRequest, NextApiResponse } from "next";
import { Session, withIronSession } from "next-iron-session";
type NextIronRequest = NextApiRequest & { session: Session };
type APIHandler = (
req: NextIronRequest,
res: NextApiResponse<any>,
) => Promise<any>;
export type ServerSideProps = ({
req,
}: {
req: NextIronRequest;
}) => Promise<any>;
const withSession = (handler: APIHandler | ServerSideProps) =>
withIronSession(handler, {
password: process.env.IRON_SESSION_PASSWORD || "",
cookieName: process.env.IRON_SESSION_COOKIE_NAME || "",
// if your localhost is served on http:// then disable the secure flag
cookieOptions: {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
},
});
export default withSession;

View file

@ -1,5 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View file

@ -1,20 +0,0 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@stytch/stytch-react": "^3.0.3",
"next": "12.0.7",
"next-iron-session": "^4.2.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"stytch": "^3.6.1"
},
"devDependencies": {
"@types/react": "17.0.37",
"typescript": "^4.5.4"
}
}

View file

@ -1,55 +0,0 @@
import "../styles/globals.css";
import styles from "../styles/Home.module.css";
import type { AppProps } from "next/app";
import React from "react";
import Head from "next/head";
import Image from "next/image";
import stytchLogo from "/public/stytch-logo.svg";
import vercelLogo from "/public/vercel-logotype-dark.svg";
function MyApp({ Component, pageProps }: AppProps) {
return (
<React.Fragment>
<Head>
<link rel="icon" href="/favicon.png" type="image/png" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
<title>Stytch + Next.js example app</title>
</Head>
<div className={styles.nav}>
<div className={styles.navLogos}>
<a
href="https://stytch.com"
rel="noopener noreferrer"
target="_blank"
>
<Image alt="Stytch logo" height={20} src={stytchLogo} width={105} />
</a>
<p className={styles.navPlusSign}> + </p>
<a
href="https://vercel.com"
rel="noopener noreferrer"
target="_blank"
>
<Image alt="Vercel logo" height={20} src={vercelLogo} width={105} />
</a>
</div>
<div className={styles.docsNavItem}>
<a
href="https://stytch.com/docs"
rel="noopener noreferrer"
target="_blank"
>
Docs
</a>
</div>
</div>
<div className={styles.root}>
<Component {...pageProps} />
</div>
</React.Fragment>
);
}
export default MyApp;

View file

@ -1,18 +0,0 @@
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html>
<Head>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;700&family=IBM+Plex+Sans:wght@400;500;600&display=swap"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

View file

@ -1,39 +0,0 @@
// This API route authenticates a Stytch magic link.
import type { NextApiRequest, NextApiResponse } from "next";
import { Session } from "next-iron-session";
import withSession from "../../lib/withSession";
import loadStytch from "../../lib/loadStytch";
type NextIronRequest = NextApiRequest & { session: Session };
type Data = {
errorString: string;
};
export async function handler(
req: NextIronRequest,
res: NextApiResponse<Data>,
) {
if (req.method === "GET") {
const client = loadStytch();
const { token } = req.query;
try {
const resp = await client.magicLinks.authenticate(token as string);
// Set session
req.session.destroy();
req.session.set("user", {
id: resp.user_id,
});
// Save additional user data here
await req.session.save();
res.redirect("/profile");
} catch (error) {
const errorString = JSON.stringify(error);
console.log(error);
res.status(400).json({ errorString });
}
} else {
// Handle any other HTTP method
}
}
export default withSession(handler);

View file

@ -1,51 +0,0 @@
// This API route authenticates Stytch OTP codes.
import type { NextApiRequest, NextApiResponse } from "next";
import { Session } from "next-iron-session";
import withSession from "../../lib/withSession";
import loadStytch from "../../lib/loadStytch";
type NextIronRequest = NextApiRequest & { session: Session };
type Data = {
msg: string;
};
export async function handler(
req: NextIronRequest,
res: NextApiResponse<Data>,
) {
if (req.method === "POST") {
const client = loadStytch();
const data = JSON.parse(req.body);
try {
// params are of type stytch.LoginOrCreateUserBySMSRequest
const params = {
code: data.otpInput,
method_id: data.methodId,
};
const resp = await client.otps.authenticate(params);
if (resp.status_code.toString() === "200") {
// Set session
req.session.destroy();
// Save additional user data here
req.session.set("user", {
id: resp.user_id,
});
await req.session.save();
res
.status(200)
.send({ msg: `successfully authenticated ${resp.user_id}` });
} else {
throw Error("Error authenticating your code");
}
} catch (error) {
const errorString = JSON.stringify(error);
console.log(error);
res.status(400).json({ msg: errorString });
}
} else {
// Handle any other HTTP method
}
}
export default withSession(handler);

View file

@ -1,30 +0,0 @@
// This API route logs a user out.
import type { NextApiRequest, NextApiResponse } from "next";
import { Session } from "next-iron-session";
import withSession from "../../lib/withSession";
type NextIronRequest = NextApiRequest & { session: Session };
type Data = {
errorString: string;
};
export async function handler(
req: NextIronRequest,
res: NextApiResponse<Data>,
) {
if (req.method === "POST") {
try {
// Set session
req.session.destroy();
res.redirect("/");
} catch (error) {
const errorString = JSON.stringify(error);
console.log(error);
res.status(400).json({ errorString });
}
} else {
// Handle any other HTTP method
}
}
export default withSession(handler);

View file

@ -1,32 +0,0 @@
// This API route sends an OTP code to a specified number.
import type { NextApiRequest, NextApiResponse } from "next";
import loadStytch from "../../lib/loadStytch";
type Data = {
methodId: string;
};
export async function handler(req: NextApiRequest, res: NextApiResponse<Data>) {
if (req.method === "POST") {
const client = loadStytch();
const data = JSON.parse(req.body);
try {
const phoneNumber = data.phoneNumber.replace(/\D/g, "");
// params are of type stytch.LoginOrCreateUserBySMSRequest
const params = {
phone_number: `${data.intlCode}${phoneNumber}`,
};
const resp = await client.otps.sms.loginOrCreate(params);
res.status(200).json({ methodId: resp.phone_id });
} catch (error) {
console.log(error);
res.status(400);
}
} else {
// Handle any other HTTP method
}
}
export default handler;

View file

@ -1,126 +0,0 @@
import React, { useEffect } from "react";
import { useRouter } from "next/router";
import { Stytch, StytchProps } from "@stytch/stytch-react";
import { OAuthProvidersTypes, SDKProductTypes } from "@stytch/stytch-js";
import styles from "../styles/Home.module.css";
import withSession, { ServerSideProps } from "../lib/withSession";
import LoginWithSMS from "../components/LoginWithSMS";
import { LoginMethod } from "../lib/types";
import LoginEntryPoint from "../components/LoginEntryPoint";
// Set the URL base for redirect URLs. The three cases are as follows:
// 1. Running locally via `vercel dev`; VERCEL_URL will contain localhost, but will not be https.
// 2. Deploying via Vercel; VERCEL_URL will be generated on runtime and use https.
// 3. Running locally via `npm run dev`; VERCEL_URL will be undefined and the app will be at localhost.
let REDIRECT_URL_BASE = "";
if (process.env.NEXT_PUBLIC_VERCEL_URL?.includes("localhost")) {
REDIRECT_URL_BASE = "http://localhost:3000";
} else if (process.env.NEXT_PUBLIC_VERCEL_URL !== undefined) {
REDIRECT_URL_BASE = `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`;
} else {
REDIRECT_URL_BASE = "http://localhost:3000";
}
const stytchProps: StytchProps = {
loginOrSignupView: {
products: [SDKProductTypes.oauth, SDKProductTypes.emailMagicLinks],
emailMagicLinksOptions: {
loginRedirectURL: REDIRECT_URL_BASE + "/api/authenticate_magic_link",
loginExpirationMinutes: 30,
signupRedirectURL: REDIRECT_URL_BASE + "/api/authenticate_magic_link",
signupExpirationMinutes: 30,
createUserAsPending: false,
},
oauthOptions: {
providers: [
{ type: OAuthProvidersTypes.Google },
{ type: OAuthProvidersTypes.Microsoft },
{ type: OAuthProvidersTypes.Apple },
],
},
},
style: {
fontFamily: '"Helvetica New", Helvetica, sans-serif',
primaryColor: "#0577CA",
primaryTextColor: "#090909",
width: "321px",
},
publicToken: process.env.NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN || "",
callbacks: {
onEvent: (data: { eventData: { userId: any; email: any } }) => {
if (
data.eventData.userId !== undefined &&
data.eventData.userId != null
) {
console.log({
userId: data.eventData.userId,
email: data.eventData.email,
});
} else {
console.warn("The user is not found. Data: ", data);
}
},
onSuccess: (data) => console.log(data),
onError: (data) => console.log(data),
},
};
type Props = {
publicToken: string;
user: {
id: string;
};
};
const App = (props: Props) => {
const { user, publicToken } = props;
const [loginMethod, setLoginMethod] = React.useState<LoginMethod | null>(
null,
);
const router = useRouter();
useEffect(() => {
if (user) {
router.push("/profile");
}
});
const loginMethodMap: Record<LoginMethod, React.ReactElement> = {
[LoginMethod.API]: <LoginWithSMS />,
[LoginMethod.SDK]: (
<div className={styles.container}>
<Stytch
publicToken={publicToken || ""}
loginOrSignupView={stytchProps.loginOrSignupView}
style={stytchProps.style}
callbacks={stytchProps.callbacks}
/>
</div>
),
};
return (
<div className={styles.root}>
{loginMethod === null ? (
<LoginEntryPoint setLoginMethod={setLoginMethod} />
) : (
loginMethodMap[loginMethod]
)}
</div>
);
};
const getServerSidePropsHandler: ServerSideProps = async ({ req }) => {
// Get the user's session based on the request
const user = req.session.get("user") ?? null;
const props: Props = {
publicToken: stytchProps.publicToken,
user,
};
return { props };
};
export const getServerSideProps = withSession(getServerSidePropsHandler);
export default App;

View file

@ -1,61 +0,0 @@
import React, { useEffect } from "react";
import styles from "../styles/Home.module.css";
import StytchContainer from "../components/StytchContainer";
import withSession, { ServerSideProps } from "../lib/withSession";
import { useRouter } from "next/router";
type Props = {
user?: {
id: string;
};
};
const Profile = (props: Props) => {
const { user } = props;
const router = useRouter();
useEffect(() => {
if (!user) {
router.replace("/");
}
});
const signOut = async () => {
const resp = await fetch("/api/logout", { method: "POST" });
if (resp.status === 200) {
router.push("/");
}
};
return (
<>
{!user ? (
<div />
) : (
<StytchContainer>
<h2>{"Welcome!"}</h2>
<p className={styles.profileSubHeader}>
Thank you for using Stytch! Heres your user info.
</p>
<pre className={styles.code}>
{JSON.stringify(user, null, 1).replace(" ", "")}
</pre>
<button className={styles.primaryButton} onClick={signOut}>
Sign out
</button>
</StytchContainer>
)}
</>
);
};
const getServerSidePropsHandler: ServerSideProps = async ({ req }) => {
// Get the user's session based on the request
const user = req.session.get("user") ?? null;
const props: Props = { user };
return { props };
};
export const getServerSideProps = withSession(getServerSidePropsHandler);
export default Profile;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

View file

@ -1,17 +0,0 @@
<svg width="471" height="45" viewBox="0 0 471 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M337.196 24.9966V39.5315H345.581V24.9966C348.034 21.1446 357.95 3.39655 358.872 1.55785H349.123C347.601 4.24695 337.196 24.9966 337.196 24.9966ZM339.373 12.5854L334.761 20.9101C332.488 16.9569 325.999 5.62597 323.919 1.53027H333.696L339.373 12.5854Z" fill="#ADBCC5"/>
<path d="M270.108 32.8665C271.1 32.886 272.091 32.7872 273.06 32.5723C273.72 32.4179 274.346 32.142 274.904 31.7587C275.343 31.4591 275.683 31.0369 275.882 30.5451C276.078 30.0394 276.179 29.5016 276.177 28.9593C276.17 28.3459 276.008 27.7444 275.704 27.2106C275.401 26.6769 274.967 26.2284 274.443 25.907C273.287 25.1103 271.299 24.2445 268.48 23.3099C267.25 22.8778 266.02 22.3813 264.791 21.8205C263.59 21.2827 262.475 20.5735 261.479 19.7152C260.494 18.8517 259.685 17.8057 259.1 16.6354C258.449 15.2618 258.133 13.7546 258.177 12.2363C258.151 10.627 258.483 9.03195 259.15 7.56604C259.793 6.19357 260.739 4.98363 261.917 4.02656C263.204 3.00622 264.678 2.24583 266.257 1.78795C268.122 1.23995 270.059 0.974963 272.003 1.0019C274.217 0.961833 276.425 1.23421 278.562 1.81093C280.136 2.24735 281.662 2.84505 283.113 3.59446L280.674 10.2367C279.55 9.66582 278.38 9.18769 277.178 8.80716C275.682 8.36466 274.126 8.15534 272.566 8.1866C270.54 8.1866 269.086 8.46547 268.203 9.02321C267.77 9.29166 267.418 9.67178 267.185 10.1233C266.951 10.5749 266.844 11.081 266.875 11.5882C266.845 12.2037 267.01 12.8129 267.346 13.3304C267.715 13.8428 268.186 14.2745 268.729 14.5991C269.38 15.0063 270.069 15.3511 270.786 15.6287C271.564 15.9352 272.423 16.2493 273.364 16.5711C275.316 17.2912 277.015 18.0022 278.46 18.7039C279.782 19.3194 280.995 20.1436 282.053 21.1448C283.004 22.0693 283.737 23.1937 284.197 24.4361C284.701 25.9153 284.94 27.4712 284.903 29.0328C284.903 32.5263 283.673 35.2353 281.213 37.1598C278.754 39.0843 275.052 40.0481 270.108 40.0512C268.604 40.0612 267.101 39.9614 265.611 39.7524C264.413 39.5839 263.227 39.3398 262.06 39.0215C261.155 38.7762 260.267 38.469 259.404 38.1022C258.666 37.7758 258.02 37.4724 257.536 37.1828L259.92 30.4854C261.243 31.178 262.634 31.7311 264.071 32.1356C266.039 32.6614 268.071 32.9075 270.108 32.8665Z" fill="#ADBCC5"/>
<path d="M319.57 1.55322V8.95857H308.179V39.5637H299.758V8.95857H287.873V1.55322H319.57Z" fill="#ADBCC5"/>
<path d="M395.144 1.55322V8.95857H383.776V39.5637H375.332V8.95857H363.447V1.55322H395.144Z" fill="#ADBCC5"/>
<path d="M416.779 40.079C410.866 40.079 406.363 38.3935 403.27 35.0226C400.177 31.6517 398.629 26.8496 398.626 20.6164C398.579 17.7947 399.059 14.9888 400.042 12.3423C400.902 10.0511 402.224 7.95953 403.925 6.19646C405.581 4.51755 407.587 3.22142 409.801 2.39955C412.16 1.52142 414.661 1.08206 417.18 1.10327C418.586 1.09346 419.991 1.21039 421.377 1.45262C422.494 1.65524 423.598 1.92542 424.683 2.26165C425.499 2.51629 426.294 2.83603 427.058 3.21777C427.69 3.53954 428.142 3.79236 428.442 3.97164L426.081 10.761C424.838 10.1032 423.528 9.5793 422.174 9.19813C420.523 8.74361 418.815 8.52538 417.101 8.54999C415.843 8.55158 414.595 8.77088 413.412 9.19813C412.199 9.63722 411.104 10.3481 410.211 11.2759C409.219 12.3332 408.46 13.5859 407.984 14.9532C407.381 16.7286 407.097 18.5958 407.144 20.4693C407.128 22.0889 407.306 23.7046 407.675 25.2821C407.998 26.6747 408.605 27.986 409.46 29.1342C410.311 30.2364 411.419 31.1153 412.688 31.6946C414.205 32.3626 415.854 32.6845 417.512 32.6369C418.583 32.6444 419.652 32.5721 420.712 32.4208C421.561 32.299 422.402 32.1271 423.231 31.906C423.893 31.7391 424.542 31.5225 425.172 31.2579C425.732 31.0035 426.239 30.7691 426.694 30.5546L428.972 37.275C427.445 38.1463 425.803 38.7993 424.093 39.2148C421.704 39.8269 419.244 40.1176 416.779 40.079Z" fill="#ADBCC5"/>
<path d="M458.124 1.60889H467.038V39.6331H458.124V23.3377H443.758V39.6331H435.332V1.60889H443.758V15.9277H458.124V1.60889Z" fill="#ADBCC5"/>
<path d="M0 35.2128V2.44186H13.052C15.9942 2.44186 18.2478 3.28696 19.8128 4.97715C21.4091 6.63604 22.2072 8.92093 22.2072 11.8318C22.2072 14.7427 21.4091 17.0432 19.8128 18.7334C18.2478 20.3923 15.9942 21.2218 13.052 21.2218H3.94378V35.2128H0ZM3.94378 17.7475H13.052C14.617 17.7475 15.8221 17.3406 16.6672 16.5268C17.5436 15.713 17.9818 14.5549 17.9818 13.0525V10.6111C17.9818 9.10873 17.5436 7.95063 16.6672 7.13684C15.8221 6.32304 14.617 5.91614 13.052 5.91614H3.94378V17.7475Z" fill="#ADBCC5"/>
<path d="M36.3351 35.7762C34.7075 35.7762 33.2208 35.4789 31.8749 34.8842C30.529 34.2895 29.3709 33.4444 28.4006 32.3489C27.4616 31.2221 26.726 29.8918 26.1939 28.3581C25.6618 26.7931 25.3958 25.0404 25.3958 23.0998C25.3958 21.1905 25.6618 19.4533 26.1939 17.8883C26.726 16.3233 27.4616 14.9931 28.4006 13.8976C29.3709 12.7708 30.529 11.9101 31.8749 11.3154C33.2208 10.7207 34.7075 10.4233 36.3351 10.4233C37.9627 10.4233 39.4338 10.7207 40.7484 11.3154C42.0943 11.9101 43.2524 12.7708 44.2227 13.8976C45.193 14.9931 45.9441 16.3233 46.4762 17.8883C47.0083 19.4533 47.2744 21.1905 47.2744 23.0998C47.2744 25.0404 47.0083 26.7931 46.4762 28.3581C45.9441 29.8918 45.193 31.2221 44.2227 32.3489C43.2524 33.4444 42.0943 34.2895 40.7484 34.8842C39.4338 35.4789 37.9627 35.7762 36.3351 35.7762ZM36.3351 32.4428C38.3696 32.4428 40.0285 31.8168 41.3118 30.5648C42.5951 29.3128 43.2367 27.4035 43.2367 24.8369V21.3626C43.2367 18.796 42.5951 16.8867 41.3118 15.6347C40.0285 14.3828 38.3696 13.7568 36.3351 13.7568C34.3006 13.7568 32.6417 14.3828 31.3584 15.6347C30.0751 16.8867 29.4335 18.796 29.4335 21.3626V24.8369C29.4335 27.4035 30.0751 29.3128 31.3584 30.5648C32.6417 31.8168 34.3006 32.4428 36.3351 32.4428Z" fill="#ADBCC5"/>
<path d="M50.6871 10.9867H54.3491L56.9314 21.4565L59.5136 32.0672H59.6075L62.5653 21.4565L65.6171 10.9867H68.9505L72.0962 21.4565L75.1009 32.0672H75.1948L77.6832 21.4565L80.3124 10.9867H83.8336L77.4015 35.2128H72.7534L69.3731 23.5693L67.2603 16.1981H67.1664L65.1006 23.5693L61.7203 35.2128H57.1661L50.6871 10.9867Z" fill="#ADBCC5"/>
<path d="M98.139 35.7762C96.4801 35.7762 94.9777 35.4789 93.6318 34.8842C92.3172 34.2895 91.1748 33.4444 90.2045 32.3489C89.2655 31.2221 88.5299 29.8918 87.9978 28.3581C87.497 26.7931 87.2466 25.0404 87.2466 23.0998C87.2466 21.1905 87.497 19.4533 87.9978 17.8883C88.5299 16.3233 89.2655 14.9931 90.2045 13.8976C91.1748 12.7708 92.3172 11.9101 93.6318 11.3154C94.9777 10.7207 96.4801 10.4233 98.139 10.4233C99.7666 10.4233 101.222 10.7207 102.505 11.3154C103.789 11.9101 104.884 12.7395 105.792 13.8037C106.699 14.8366 107.388 16.0729 107.858 17.5127C108.358 18.9525 108.609 20.5332 108.609 22.2547V24.0388H91.1904V25.1656C91.1904 26.1985 91.3469 27.1687 91.6599 28.0764C92.0042 28.9528 92.4737 29.7197 93.0684 30.377C93.6944 31.0343 94.4456 31.5507 95.322 31.9263C96.2297 32.3019 97.2469 32.4897 98.3737 32.4897C99.9074 32.4897 101.238 32.1298 102.364 31.4099C103.523 30.69 104.415 29.6571 105.041 28.3112L107.717 30.2361C106.934 31.895 105.714 33.2409 104.055 34.2738C102.396 35.2754 100.424 35.7762 98.139 35.7762ZM98.139 13.569C97.1061 13.569 96.1671 13.7568 95.322 14.1324C94.4769 14.4767 93.7413 14.9775 93.1153 15.6347C92.5207 16.292 92.0512 17.0745 91.7069 17.9822C91.3626 18.8586 91.1904 19.8289 91.1904 20.8931V21.2218H104.571V20.7053C104.571 18.5456 103.976 16.8241 102.787 15.5408C101.629 14.2263 100.08 13.569 98.139 13.569Z" fill="#ADBCC5"/>
<path d="M114.798 35.2128V10.9867H118.554V15.4469H118.789C119.227 14.2889 120.01 13.256 121.136 12.3483C122.263 11.4406 123.812 10.9867 125.784 10.9867H127.24V14.7427H125.033C122.999 14.7427 121.402 15.134 120.244 15.9164C119.117 16.6676 118.554 17.6223 118.554 18.7804V35.2128H114.798Z" fill="#ADBCC5"/>
<path d="M140.916 35.7762C139.258 35.7762 137.755 35.4789 136.409 34.8842C135.095 34.2895 133.952 33.4444 132.982 32.3489C132.043 31.2221 131.307 29.8918 130.775 28.3581C130.275 26.7931 130.024 25.0404 130.024 23.0998C130.024 21.1905 130.275 19.4533 130.775 17.8883C131.307 16.3233 132.043 14.9931 132.982 13.8976C133.952 12.7708 135.095 11.9101 136.409 11.3154C137.755 10.7207 139.258 10.4233 140.916 10.4233C142.544 10.4233 143.999 10.7207 145.283 11.3154C146.566 11.9101 147.662 12.7395 148.569 13.8037C149.477 14.8366 150.166 16.0729 150.635 17.5127C151.136 18.9525 151.386 20.5332 151.386 22.2547V24.0388H133.968V25.1656C133.968 26.1985 134.124 27.1687 134.437 28.0764C134.782 28.9528 135.251 29.7197 135.846 30.377C136.472 31.0343 137.223 31.5507 138.099 31.9263C139.007 32.3019 140.024 32.4897 141.151 32.4897C142.685 32.4897 144.015 32.1298 145.142 31.4099C146.3 30.69 147.192 29.6571 147.818 28.3112L150.494 30.2361C149.712 31.895 148.491 33.2409 146.832 34.2738C145.173 35.2754 143.201 35.7762 140.916 35.7762ZM140.916 13.569C139.884 13.569 138.945 13.7568 138.099 14.1324C137.254 14.4767 136.519 14.9775 135.893 15.6347C135.298 16.292 134.829 17.0745 134.484 17.9822C134.14 18.8586 133.968 19.8289 133.968 20.8931V21.2218H147.349V20.7053C147.349 18.5456 146.754 16.8241 145.564 15.5408C144.406 14.2263 142.857 13.569 140.916 13.569Z" fill="#ADBCC5"/>
<path d="M173.069 31.269H172.881C171.41 34.2738 169.047 35.7762 165.792 35.7762C164.289 35.7762 162.928 35.4789 161.707 34.8842C160.486 34.2895 159.438 33.4444 158.562 32.3489C157.716 31.2534 157.059 29.9231 156.59 28.3581C156.151 26.7931 155.932 25.0404 155.932 23.0998C155.932 21.1592 156.151 19.4064 156.59 17.8414C157.059 16.2764 157.716 14.9462 158.562 13.8507C159.438 12.7552 160.486 11.9101 161.707 11.3154C162.928 10.7207 164.289 10.4233 165.792 10.4233C167.482 10.4233 168.922 10.7989 170.111 11.5501C171.332 12.27 172.255 13.3968 172.881 14.9305H173.069V0.469971H176.825V35.2128H173.069V31.269ZM166.825 32.3958C167.67 32.3958 168.468 32.2863 169.219 32.0672C170.002 31.8481 170.675 31.5351 171.238 31.1282C171.801 30.69 172.24 30.1735 172.553 29.5788C172.897 28.9528 173.069 28.2486 173.069 27.4661V18.4517C173.069 17.7944 172.897 17.1841 172.553 16.6207C172.24 16.026 171.801 15.5252 171.238 15.1183C170.675 14.7114 170.002 14.3984 169.219 14.1793C168.468 13.9289 167.67 13.8037 166.825 13.8037C164.696 13.8037 163.022 14.4767 161.801 15.8225C160.58 17.1371 159.97 18.8743 159.97 21.034V25.1656C159.97 27.3252 160.58 29.078 161.801 30.4239C163.022 31.7385 164.696 32.3958 166.825 32.3958Z" fill="#ADBCC5"/>
<path d="M195.906 0.469971H199.662V14.9305H199.849C200.475 13.3968 201.383 12.27 202.573 11.5501C203.793 10.7989 205.249 10.4233 206.939 10.4233C208.441 10.4233 209.803 10.7207 211.023 11.3154C212.244 11.9101 213.277 12.7552 214.122 13.8507C214.999 14.9462 215.656 16.2764 216.094 17.8414C216.564 19.4064 216.798 21.1592 216.798 23.0998C216.798 25.0404 216.564 26.7931 216.094 28.3581C215.656 29.9231 214.999 31.2534 214.122 32.3489C213.277 33.4444 212.244 34.2895 211.023 34.8842C209.803 35.4789 208.441 35.7762 206.939 35.7762C203.652 35.7762 201.289 34.2738 199.849 31.269H199.662V35.2128H195.906V0.469971ZM205.906 32.3958C208.034 32.3958 209.709 31.7385 210.93 30.4239C212.15 29.078 212.761 27.3252 212.761 25.1656V21.034C212.761 18.8743 212.15 17.1371 210.93 15.8225C209.709 14.4767 208.034 13.8037 205.906 13.8037C205.061 13.8037 204.247 13.9289 203.465 14.1793C202.713 14.3984 202.056 14.7114 201.493 15.1183C200.929 15.5252 200.475 16.026 200.131 16.6207C199.818 17.1841 199.662 17.7944 199.662 18.4517V27.4661C199.662 28.2486 199.818 28.9528 200.131 29.5788C200.475 30.1735 200.929 30.69 201.493 31.1282C202.056 31.5351 202.713 31.8481 203.465 32.0672C204.247 32.2863 205.061 32.3958 205.906 32.3958Z" fill="#ADBCC5"/>
<path d="M237.841 10.9867H241.55L230.705 40.8468C230.423 41.5667 230.141 42.1614 229.86 42.6309C229.578 43.1317 229.234 43.5229 228.827 43.8046C228.42 44.0863 227.903 44.2898 227.277 44.415C226.683 44.5402 225.947 44.6028 225.071 44.6028H223.146V41.3163H226.949L228.78 36.1518L219.718 10.9867H223.474L229.296 27.4661L230.423 31.4099H230.658L231.972 27.4661L237.841 10.9867Z" fill="#ADBCC5"/>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 B

View file

@ -1,8 +0,0 @@
<svg width="690" height="131" viewBox="0 0 690 131" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M263.847 79.7113V126.06H290.495V79.7113C298.294 67.4277 329.809 10.8326 332.74 4.9693H301.753C296.916 13.5443 263.847 79.7113 263.847 79.7113ZM270.765 40.1342L256.107 66.6802C248.881 54.0741 228.257 17.9418 221.646 4.88135H252.721L270.765 40.1342Z" fill="#19303D"/>
<path d="M50.6146 104.806C53.7679 104.868 56.9173 104.554 59.9959 103.868C62.0948 103.376 64.0833 102.496 65.8591 101.274C67.2538 100.318 68.3349 98.9719 68.9667 97.4039C69.591 95.7912 69.9091 94.0762 69.9048 92.3468C69.8828 90.3911 69.3659 88.4727 68.4021 86.7708C67.4384 85.0688 66.0592 83.6387 64.3933 82.6138C60.719 80.0731 54.4013 77.3124 45.4403 74.332C41.5315 72.9541 37.6226 71.371 33.7138 69.5827C29.8983 67.8678 26.3529 65.6062 23.1892 62.8693C20.0566 60.1156 17.488 56.7803 15.6256 53.0483C13.5584 48.6681 12.554 43.8619 12.694 39.0204C12.6112 33.8886 13.6675 28.8023 15.7869 24.1277C17.8311 19.7512 20.8376 15.8929 24.5818 12.841C28.6717 9.58731 33.3569 7.16254 38.3751 5.70244C44.3028 3.95497 50.4598 3.10998 56.6392 3.19589C63.674 3.06811 70.6916 3.93667 77.4831 5.77573C82.4889 7.1674 87.3372 9.07334 91.9507 11.4631L84.1965 32.6441C80.6236 30.8235 76.9076 29.2989 73.0856 28.0855C68.3307 26.6744 63.3863 26.0069 58.4275 26.1066C51.9876 26.1066 47.3654 26.9959 44.5608 28.7744C43.1851 29.6304 42.0664 30.8425 41.3232 32.2824C40.5801 33.7223 40.2401 35.3363 40.3393 36.9536C40.2445 38.9162 40.7674 40.8592 41.8344 42.5091C43.0094 44.1431 44.5058 45.5198 46.2319 46.5547C48.3023 47.8534 50.4913 48.9528 52.7694 49.8382C55.2417 50.8154 57.973 51.817 60.9633 52.8431C67.1686 55.1395 72.5677 57.4067 77.1606 59.6445C81.3612 61.6069 85.2172 64.2353 88.5793 67.428C91.6036 70.3759 93.9322 73.9614 95.3953 77.9232C96.9959 82.6401 97.755 87.6017 97.638 92.5814C97.638 103.722 93.7292 112.36 85.9115 118.497C78.0938 124.634 66.3282 127.707 50.6146 127.717C45.8339 127.749 41.0572 127.431 36.3229 126.764C32.5152 126.227 28.7453 125.448 25.0362 124.434C22.1579 123.651 19.3369 122.672 16.5931 121.502C14.2478 120.461 12.1956 119.494 10.6565 118.57L18.2348 97.2134C22.437 99.422 26.8585 101.186 31.4271 102.476C37.6813 104.152 44.141 104.937 50.6146 104.806Z" fill="#19303D"/>
<path d="M207.823 4.95435V28.5686H171.618V126.163H144.852V28.5686H107.078V4.95435H207.823Z" fill="#19303D"/>
<path d="M448.027 4.95435V28.5686H411.894V126.163H385.055V28.5686H347.281V4.95435H448.027Z" fill="#19303D"/>
<path d="M516.788 127.805C497.996 127.805 483.685 122.43 473.854 111.681C464.024 100.931 459.103 85.6183 459.094 65.7419C458.942 56.7438 460.468 47.7964 463.594 39.3572C466.327 32.0508 470.528 25.3813 475.936 19.7592C481.2 14.4055 487.574 10.2724 494.61 7.65156C502.109 4.85135 510.059 3.45031 518.063 3.51796C522.534 3.48668 526.999 3.85953 531.402 4.63198C534.955 5.2781 538.464 6.13963 541.912 7.21182C544.506 8.02383 547.031 9.04342 549.461 10.2607C551.469 11.2868 552.906 12.093 553.859 12.6647L546.354 34.3148C542.404 32.2172 538.242 30.5465 533.938 29.331C528.689 27.8816 523.26 27.1857 517.814 27.2642C513.815 27.2693 509.847 27.9686 506.088 29.331C502.234 30.7312 498.754 32.998 495.915 35.9565C492.762 39.3281 490.35 43.3227 488.835 47.683C486.921 53.3444 486.018 59.2984 486.167 65.2728C486.116 70.4374 486.682 75.5896 487.853 80.6199C488.88 85.0607 490.811 89.2421 493.526 92.9034C496.232 96.4183 499.753 99.2207 503.786 101.068C508.61 103.198 513.848 104.225 519.119 104.073C522.522 104.097 525.922 103.866 529.292 103.384C531.989 102.996 534.662 102.447 537.295 101.742C539.401 101.21 541.464 100.519 543.466 99.6755C545.245 98.8644 546.857 98.1169 548.303 97.4328L555.544 118.863C550.69 121.642 545.47 123.724 540.036 125.049C532.444 127.001 524.626 127.927 516.788 127.805Z" fill="#19303D"/>
<path d="M648.199 5.13037H676.533V126.383H648.199V74.4195H602.538V126.383H575.758V5.13037H602.538V50.7906H648.199V5.13037Z" fill="#19303D"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,3 +0,0 @@
<svg width="4438" height="1000" viewBox="0 0 4438 1000" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2223.75 250C2051.25 250 1926.87 362.5 1926.87 531.25C1926.87 700 2066.72 812.5 2239.38 812.5C2343.59 812.5 2435.47 771.25 2492.34 701.719L2372.81 632.656C2341.25 667.188 2293.28 687.344 2239.38 687.344C2164.53 687.344 2100.94 648.281 2077.34 585.781H2515.16C2518.59 568.281 2520.63 550.156 2520.63 531.094C2520.63 362.5 2396.41 250 2223.75 250ZM2076.09 476.562C2095.62 414.219 2149.06 375 2223.75 375C2298.59 375 2352.03 414.219 2371.41 476.562H2076.09ZM2040.78 78.125L1607.81 828.125L1174.69 78.125H1337.03L1607.66 546.875L1878.28 78.125H2040.78ZM577.344 0L1154.69 1000H0L577.344 0ZM3148.75 531.25C3148.75 625 3210 687.5 3305 687.5C3369.38 687.5 3417.66 658.281 3442.5 610.625L3562.5 679.844C3512.81 762.656 3419.69 812.5 3305 812.5C3132.34 812.5 3008.13 700 3008.13 531.25C3008.13 362.5 3132.5 250 3305 250C3419.69 250 3512.66 299.844 3562.5 382.656L3442.5 451.875C3417.66 404.219 3369.38 375 3305 375C3210.16 375 3148.75 437.5 3148.75 531.25ZM4437.5 78.125V796.875H4296.88V78.125H4437.5ZM3906.25 250C3733.75 250 3609.38 362.5 3609.38 531.25C3609.38 700 3749.38 812.5 3921.88 812.5C4026.09 812.5 4117.97 771.25 4174.84 701.719L4055.31 632.656C4023.75 667.188 3975.78 687.344 3921.88 687.344C3847.03 687.344 3783.44 648.281 3759.84 585.781H4197.66C4201.09 568.281 4203.12 550.156 4203.12 531.094C4203.12 362.5 4078.91 250 3906.25 250ZM3758.59 476.562C3778.13 414.219 3831.41 375 3906.25 375C3981.09 375 4034.53 414.219 4053.91 476.562H3758.59ZM2961.25 265.625V417.031C2945.63 412.5 2929.06 409.375 2911.25 409.375C2820.47 409.375 2755 471.875 2755 565.625V796.875H2614.38V265.625H2755V409.375C2755 330 2847.34 265.625 2961.25 265.625Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,3 @@
## Stytch with Next.js
You can follow the guide on the [Stytch documentation](https://stytch.com/docs/sdks/javascript-sdk/installation).

View file

@ -1,194 +0,0 @@
.root {
background-color: #ecfaff;
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.container {
background-color: white;
border: 1px solid #ebebeb;
border-radius: 9px;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.12);
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 80px;
width: 500px;
height: 500px;
}
@media only screen and (max-width: 600px) {
.container {
border: none;
border-radius: 0;
box-shadow: none;
width: 100%;
}
}
@media only screen and (max-width: 400px) {
.container {
padding: 40px;
}
}
.primaryButton {
background-color: #19303d;
}
.primaryButton:disabled {
background-color: #f3f5f6;
color: #5c727d;
opacity: 1;
}
/* Nav bar styles */
.nav {
align-items: center;
background-color: #c7f1ff;
display: flex;
height: 64px;
justify-content: space-between;
padding: 0 28px;
position: absolute;
top: 0;
width: 100%;
}
.navLogos {
align-items: center;
background-color: #c7f1ff;
display: flex;
height: 64px;
padding: 0 28px;
top: 0;
}
.navPlusSign {
padding: 0px 20px 10px 20px;
font-size: 30px;
}
.docsNavItem {
cursor: pointer;
font-size: 20px;
font-weight: 500;
line-height: 30px;
}
/* App entry styles */
.entrySubHeader {
margin: 32px 0;
}
.entryButton {
background-color: #e5e8eb;
color: #19303d;
margin-bottom: 16px;
}
/* SMS login styles */
.smsInstructions {
margin-top: 28px;
}
.smsDisclaimer {
color: #5c727d;
font-size: 14px;
line-height: 20px;
margin-bottom: 16px;
margin-top: 24px;
}
.telInput {
display: flex;
margin-top: 20px;
white-space: nowrap;
}
.flag {
background: url("/stars-and-stripes.png") no-repeat scroll 8px 16px;
border-right: none;
border-radius: 3px 0 0 3px;
width: 80px;
padding-left: 48px;
}
.phoneNumber {
border-left: none;
border-radius: 0 3px 3px 0;
padding-left: 0;
flex-grow: 1;
font-size: 18px;
width: calc(100%);
}
.passcodeContainer {
margin-top: 4px;
}
.passcodeInputContainer {
align-items: center;
display: flex;
justify-content: space-between;
width: 100%;
}
.passcodeInput {
border-radius: 3px;
font-size: 20px;
width: 48px;
height: 45px;
text-align: center;
}
.errorText {
color: red;
font-size: 14px;
height: 20px;
line-height: 20px;
}
.resendCodeContainer {
margin: 28px 0;
}
.resendCodeText {
color: #5c727d;
display: inline;
font-size: 16px;
line-height: 20px;
}
.resendCodeButton {
background-color: white;
border: none;
cursor: pointer;
font-weight: 500;
height: fit-content;
padding: 0;
width: fit-content;
}
/* Profile styles */
.profileSubHeader {
margin-bottom: 8px;
margin-top: 28px;
}
.code {
background: #f3f5f6;
border-radius: 5px;
color: #10232e;
padding: 8px;
font-size: 16px;
font-family: IBM Plex Mono, monospace;
margin-bottom: 16px;
white-space: pre-wrap;
}

View file

@ -1,73 +0,0 @@
html,
body {
padding: 0;
margin: 0;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
font-family: IBM Plex Sans, "sans-serif";
}
p {
color: #19303d;
font-size: 18px;
line-height: 25px;
margin: 0;
}
strong {
color: black;
font-weight: 500;
}
h2 {
font-size: 30px;
line-height: 40px;
margin: 0;
}
input {
border: 1px solid #adbcc5;
box-sizing: border-box;
border-radius: 3px;
color: #19303d;
font-size: 18px;
height: 45px;
line-height: 25px;
padding: 10px;
}
input:disabled {
background-color: white;
color: #19303d;
}
input:focus {
outline: 0;
}
input::placeholder {
color: #adbcc5;
}
button,
input[type="submit"] {
border: none;
border-radius: 3px;
color: white;
font-size: 18px;
font-weight: 600;
height: 45px;
width: 100%;
}
button:hover,
input[type="submit"]:hover {
opacity: 0.8;
}

View file

@ -1,20 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}