Skip to content

Commit

Permalink
docs: convert next example to use app dir
Browse files Browse the repository at this point in the history
  • Loading branch information
porcellus committed Jul 17, 2023
1 parent d2bf8ce commit 4606d62
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 1,243 deletions.
8 changes: 8 additions & 0 deletions examples/next/with-emailpassword/app/api/user-id/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { NextResponse, NextRequest } from "next/server";

export async function GET(request: NextRequest) {
let userId = request.headers.get("x-user-id");
return NextResponse.json({
userId,
});
}
18 changes: 18 additions & 0 deletions examples/next/with-emailpassword/app/api/user/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextResponse, NextRequest } from "next/server";
import { withSession } from "../../../middleware";

export async function GET(request: NextRequest) {
return withSession(request, async (session) => {
if (session === undefined) {
return new NextResponse("Authentication required", {
status: 401,
});
}
return NextResponse.json({
note: "Fetch any data from your application for authenticated user after using verifySession middleware",
userId: session.getUserId(),
sessionHandle: session.getHandle(),
accessTokenPayload: session.getAccessTokenPayload(),
});
});
}
19 changes: 19 additions & 0 deletions examples/next/with-emailpassword/app/auth/[[...path]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";
import { useEffect } from "react";
import { redirectToAuth } from "supertokens-auth-react";
import SuperTokens from "supertokens-auth-react/ui";
import { PreBuiltUIList } from "../../../config/frontendConfig";

export default function Auth() {
// if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
useEffect(() => {
if (SuperTokens.canHandleRoute(PreBuiltUIList) === false) {
redirectToAuth();
}
}, []);

if (typeof window !== "undefined") {
return SuperTokens.getRoutingComponent(PreBuiltUIList);
}
return null;
}
23 changes: 23 additions & 0 deletions examples/next/with-emailpassword/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client";
import SuperTokensReact, { SuperTokensWrapper } from "supertokens-auth-react";
import { frontendConfig } from "../config/frontendConfig";

// export const metadata = {
// title: 'Next.js',
// description: 'Generated by Next.js',
// }

if (typeof window !== "undefined") {
// we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
SuperTokensReact.init(frontendConfig());
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<SuperTokensWrapper>
<body suppressHydrationWarning={true}>{children}</body>
</SuperTokensWrapper>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
import React from "react";
import Head from "next/head";
import styles from "../styles/ProtectedHome.module.css";
import SessionReact from "supertokens-auth-react/recipe/session";
import SuperTokensReact from "supertokens-auth-react";
import { useSessionContext } from "supertokens-auth-react/recipe/session";
import { SessionAuth, useSessionContext, signOut } from "supertokens-auth-react/recipe/session";
import { redirectToAuth } from "supertokens-auth-react";
import { BlogsIcon, CelebrateIcon, GuideIcon, SeparatorLine, SignOutIcon } from "../assets/images";
import Image from "next/image";
import { recipeDetails } from "../config/frontendConfig";
Expand All @@ -18,8 +18,8 @@ function ProtectedPage() {
const session = useSessionContext();

async function logoutClicked() {
await SessionReact.signOut();
SuperTokensReact.redirectToAuth();
await signOut();
redirectToAuth();
}

async function fetchUserData() {
Expand Down Expand Up @@ -89,10 +89,10 @@ function ProtectedPage() {
);
}

export default function Home(props) {
export default function Home() {
return (
<SessionReact.SessionAuth>
<SessionAuth>
<ProtectedPage />
</SessionReact.SessionAuth>
</SessionAuth>
);
}
13 changes: 0 additions & 13 deletions examples/next/with-emailpassword/config/frontendConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,13 @@ import EmailPasswordReact from "supertokens-auth-react/recipe/emailpassword";
import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui";
import SessionReact from "supertokens-auth-react/recipe/session";
import { appInfo } from "./appInfo";
import Router from "next/router";

export let frontendConfig = () => {
return {
appInfo,
// recipeList contains all the modules that you want to
// use from SuperTokens. See the full list here: https://supertokens.com/docs/guides
recipeList: [EmailPasswordReact.init(), SessionReact.init()],
// this is so that the SDK uses the next router for navigation
windowHandler: (oI) => {
return {
...oI,
location: {
...oI.location,
setHref: (href) => {
Router.push(href);
},
},
};
},
};
};

Expand Down
67 changes: 67 additions & 0 deletions examples/next/with-emailpassword/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import Session, { SessionContainer } from "supertokens-node/recipe/session";
import supertokens from "supertokens-node";
import { backendConfig } from "./config/backendConfig";

supertokens.init(backendConfig());

export async function middleware(request: NextRequest & { session?: SessionContainer }) {
if (request.nextUrl.pathname.startsWith("/api/auth")) {
// this hits our pages/api/auth/* endpoints
return NextResponse.next();
}

return withSession(request, async (session) => {
if (session === undefined) {
return NextResponse.next();
}
return NextResponse.next({
headers: {
"x-user-id": session.getUserId(),
},
});
});
}

export const config = {
matcher: "/api/:path*",
};

export async function withSession(
request: NextRequest,
handler: (session: SessionContainer | undefined) => Promise<NextResponse>
) {
try {
const token = request.cookies.get("sAccessToken");
if (token === undefined) {
return handler(undefined);
}
const accessToken = token.value;
let session = await Session.getSessionWithoutRequestResponse(accessToken, undefined, {
sessionRequired: false,
});
let response = await handler(session);
if (session !== undefined) {
let tokens = session.getAllSessionTokensDangerously();
if (tokens.accessAndFrontTokenUpdated) {
response.cookies.set({
name: "sAccessToken",
value: tokens.accessToken,
httpOnly: true,
path: "/",
expires: Date.now() + 3153600000000,
});
response.headers.append("front-token", tokens.frontToken);
}
}
return response;
} catch (err) {
if (Session.Error.isErrorFromSuperTokens(err)) {
return new Response("Authentication required", {
status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
});
}
throw err;
}
}
3 changes: 3 additions & 0 deletions examples/next/with-emailpassword/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
experimental: {
appDir: true,
},
};

module.exports = nextConfig;
Loading

0 comments on commit 4606d62

Please sign in to comment.