Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.

Commit 722949a

Browse files
authored
Example with next.js 13.4 app directory written in typescript (#6)
* added app directory example * added example env * removed it * app-directory-ts-13.4 * changed logout code and removed comments * changed serAction to usepassageidentity/passage-js * removed "/passage-node" & added updated Readme * Removed logout button from unauthorized block * removed all unnecessary console.log * added middleware with protected routes * fixed middleware by authenticating
1 parent 1dd8561 commit 722949a

29 files changed

+8345
-0
lines changed

03-Login-app-directory/.env.example

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
NEXT_PUBLIC_PASSAGE_APP_ID=

03-Login-app-directory/.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

03-Login-app-directory/.gitignore

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env*.local
29+
30+
# vercel
31+
.vercel
32+
33+
# typescript
34+
*.tsbuildinfo
35+
next-env.d.ts

03-Login-app-directory/README.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Passage + Next.js 13.4 App Router Example
2+
3+
4+
## Getting Started
5+
6+
### Either fork the repo or directly clone it
7+
8+
### To directly clone the repo
9+
10+
```shell
11+
git clone https://github.com/passageidentity/example-nextjs.git
12+
```
13+
Then
14+
15+
```shell
16+
cd 03-Login-app-directory
17+
```
18+
19+
### Install packages
20+
21+
```shell
22+
npm i
23+
```
24+
25+
### Setup .env file
26+
27+
```js
28+
NEXT_PUBLIC_PASSAGE_APP_ID=
29+
```
30+
31+
### Start the app
32+
33+
```shell
34+
npm run dev
35+
```
36+
37+
## Available commands
38+
39+
Running commands with npm `npm run [command]`
40+
41+
| command | description |
42+
| :-------------- | :--------------------------------------- |
43+
| `dev` | Starts a development instance of the app |
44+
| `build` | To build your application |
45+
| `start` | Starts a production instance of the app |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Passage } from "@passageidentity/passage-js";
2+
3+
export interface PassageUserInfo {
4+
email: string;
5+
created_at: string;
6+
}
7+
8+
export async function getCurrentUserInfo() {
9+
const passage = new Passage(process.env.NEXT_PUBLIC_PASSAGE_APP_ID!);
10+
try {
11+
const user = passage.getCurrentUser();
12+
const userInfo = await user.userInfo();
13+
return {
14+
userInfo,
15+
};
16+
} catch (error) {
17+
console.log(error);
18+
}
19+
return { userInfo: undefined };
20+
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Link from "next/link";
2+
import { FC } from "react";
3+
4+
interface pageProps {}
5+
6+
const page: FC<pageProps> = ({}) => {
7+
return (
8+
<>
9+
<main className="flex flex-col items-center justify-center p-24 ">
10+
<h1>
11+
This is a route protected by the middleware. Should not be visible if
12+
the user is not logged in
13+
</h1>
14+
<div className="mt-10 flex flex-col items-center">
15+
<Link href="/">Back to Home</Link>
16+
<Link href="/dashboard" className="mt-5">
17+
Back to Dashboard
18+
</Link>
19+
<Link href="/blog" className="mt-5">
20+
Blog (protected route)
21+
</Link>
22+
</div>
23+
</main>
24+
</>
25+
);
26+
};
27+
28+
export default page;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Link from "next/link";
2+
import { FC } from "react";
3+
4+
interface pageProps {}
5+
6+
const page: FC<pageProps> = ({}) => {
7+
return (
8+
<>
9+
<main className="flex flex-col items-center justify-center p-24 ">
10+
<h1>Blog Slug page</h1>
11+
<h1>
12+
This is a route protected by the middleware. Should not be visible if
13+
the user is not logged in
14+
</h1>
15+
<div className="mt-10 flex flex-col items-center">
16+
<Link href="/">Back to Home</Link>
17+
<Link href="/dashboard" className="mt-5">
18+
Back to Dashboard
19+
</Link>
20+
<Link href="/blog" className="mt-5">
21+
Back to Blog Home (protected)
22+
</Link>
23+
<Link href="/about" className="mt-5">
24+
About (protected route)
25+
</Link>
26+
27+
</div>
28+
</main>
29+
</>
30+
);
31+
};
32+
33+
export default page;
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Link from "next/link";
2+
import { FC } from "react";
3+
4+
interface pageProps {}
5+
6+
const page: FC<pageProps> = ({}) => {
7+
return (
8+
<>
9+
<main className="flex flex-col items-center justify-center p-24 ">
10+
<h1>
11+
This is a route protected by the middleware. Should not be visible if
12+
the user is not logged in
13+
</h1>
14+
<div className="mt-10 flex flex-col items-center">
15+
<Link href="/">Back to Home</Link>
16+
<Link href="/dashboard" className="mt-5">
17+
Back to Dashboard
18+
</Link>
19+
<Link href="/about" className="mt-5">
20+
About (protected route)
21+
</Link>
22+
<Link href="/blog/3" className="mt-5">
23+
Blog Slog Page (protected route)
24+
</Link>
25+
</div>
26+
</main>
27+
</>
28+
);
29+
};
30+
31+
export default page;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { FC } from "react";
2+
import DashboardContent from "@/components/DashboardContent";
3+
import Link from "next/link";
4+
5+
interface pageProps {}
6+
7+
const page: FC<pageProps> = ({}) => {
8+
return (
9+
<>
10+
<DashboardContent />
11+
<div className="mt-10 mb-20 flex flex-col items-center">
12+
<Link href="/">Back to Home</Link>
13+
<Link href="/blog" className="mt-5">
14+
Blog(protected route)
15+
</Link>
16+
</div>
17+
</>
18+
);
19+
};
20+
21+
export default page;
4.19 KB
Binary file not shown.
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+

03-Login-app-directory/app/layout.tsx

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Banner from "@/components/banner";
2+
import "./globals.css";
3+
import { Inter } from "next/font/google";
4+
import Footer from "@/components/footer";
5+
6+
const inter = Inter({ subsets: ["latin"] });
7+
8+
export const metadata = {
9+
title: "Passage + Next.js Example With /app directory",
10+
description:
11+
"This is an example of how you can integrate passage with the Next.Js /app directory to Register, Login and also get Authentication Status and User Information.",
12+
};
13+
14+
export default function RootLayout({
15+
children,
16+
}: {
17+
children: React.ReactNode;
18+
}) {
19+
return (
20+
<html lang="en">
21+
<body className={inter.className}>
22+
<Banner />
23+
{children}
24+
<Footer />
25+
</body>
26+
</html>
27+
);
28+
}

03-Login-app-directory/app/page.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Auth from "@/components/Auth";
2+
import Link from "next/link";
3+
4+
export default function Home() {
5+
return (
6+
<>
7+
<Auth />
8+
<main className="flex flex-col items-center justify-center p-24 ">
9+
<div>Routes in this application</div>
10+
<Link href="/">Home</Link>
11+
<Link href="/dashboard">Dashboard</Link>
12+
<h1>Middleware Protected routes</h1>
13+
<Link href="/blog">Blog</Link>
14+
<Link href="/about">About</Link>
15+
</main>
16+
</>
17+
);
18+
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"use client";
2+
import { FC, useEffect } from "react";
3+
4+
interface AuthProps {}
5+
6+
const Auth: FC<AuthProps> = () => {
7+
useEffect(() => {
8+
require("@passageidentity/passage-elements/passage-auth");
9+
}, []);
10+
return (
11+
<>
12+
<passage-auth app-id={process.env.NEXT_PUBLIC_PASSAGE_APP_ID}></passage-auth>
13+
</>
14+
);
15+
};
16+
17+
export default Auth;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"use client";
2+
import { FC, useEffect, useState } from "react";
3+
import { getCurrentUserInfo, PassageUserInfo } from "@/actions/getCurrentUserInfo";
4+
import LogoutButton from "./LogoutButton";
5+
import Link from "next/link";
6+
import { format } from "date-fns";
7+
8+
interface DashboardContentProps {}
9+
10+
const DashboardContent: FC<DashboardContentProps> = ({}) => {
11+
const [userInfo, setUserInfo] = useState<PassageUserInfo | undefined>(
12+
undefined
13+
);
14+
const [isLoading, setIsLoading] = useState(true);
15+
16+
useEffect(() => {
17+
const fetchSessionInfo = async () => {
18+
const sessionInfo = await getCurrentUserInfo();
19+
setUserInfo(sessionInfo.userInfo);
20+
setIsLoading(false);
21+
};
22+
23+
fetchSessionInfo();
24+
}, []);
25+
26+
if (isLoading) {
27+
// Render loading state if the session information is still being fetched
28+
return <div>Loading...</div>;
29+
}
30+
31+
if (!userInfo) {
32+
// Render the message if the session doesn't exist
33+
return (
34+
<main className="flex justify-center p-24 ">
35+
<div className="border flex justify-center border-black rounded-xl w-96">
36+
<div className="p-10 pb-5">
37+
<div className="font-bold text-2xl mb-5">
38+
<h1>Unauthorized</h1>
39+
</div>
40+
<div className="break-normal"></div>
41+
<p>
42+
You have not logged in and cannot view the dashboard.
43+
<br />
44+
<Link
45+
href="/"
46+
className="underline font-bold hover:text-blue-600 "
47+
>
48+
Login to continue.
49+
</Link>
50+
</p>
51+
</div>
52+
</div>
53+
</main>
54+
);
55+
}
56+
57+
const formattedCreatedAt = format(
58+
new Date(userInfo.created_at),
59+
"yyyy-MM-dd HH:mm:ss"
60+
);
61+
62+
return (
63+
<>
64+
<main className="flex justify-center p-24 ">
65+
<div className="border flex justify-center border-black rounded-xl w-96">
66+
<div className="p-10 pb-5">
67+
<div className="font-bold text-2xl mb-5">
68+
<h1>Welcome</h1>
69+
</div>
70+
<div className="break-normal"></div>
71+
<p>
72+
You successfully signed in with Passage.
73+
<br />
74+
Your username is: <b> {userInfo.email}</b>
75+
<br />
76+
Account created at:
77+
<br /> <b> {formattedCreatedAt}</b>
78+
</p>
79+
<LogoutButton />
80+
</div>
81+
</div>
82+
</main>
83+
</>
84+
);
85+
};
86+
87+
export default DashboardContent;

0 commit comments

Comments
 (0)