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

docs(Examples): Add examples for Pages Router #631

Merged
merged 5 commits into from
Nov 21, 2023
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
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
<small><i>Psst: This README is for `iron-session` v8 which brings full Next.js App Router compatibility. The previous documentation is [here](https://github.com/vvo/iron-session/tree/v6)</i></small>
<small><i>Psst: This README is for `iron-session` v8 which brings full Next.js App Router compatibility. The previous documentation is [here](https://github.com/vvo/iron-session/tree/v6)</i></small>.

# iron-session [![GitHub license](https://img.shields.io/github/license/vvo/iron-session?style=flat)](https://github.com/vvo/iron-session/blob/master/LICENSE) [![npm](https://img.shields.io/npm/v/iron-session)](https://www.npmjs.com/package/iron-session) [![Downloads](https://img.shields.io/npm/dm/next-iron-session.svg)](http://npm-stat.com/charts.html?package=iron-session)
---

**`iron-session` is a secure, stateless, and cookie-based session library for JavaScript.**
# iron-session ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/vvo/iron-session/ci.yaml) [![GitHub license](https://img.shields.io/github/license/vvo/iron-session?style=flat)](https://github.com/vvo/iron-session/blob/master/LICENSE) [![npm](https://img.shields.io/npm/v/iron-session)](https://www.npmjs.com/package/iron-session) [![Downloads](https://img.shields.io/npm/dm/next-iron-session.svg)](http://npm-stat.com/charts.html?package=iron-session) ![npm package minimized gzipped size (select exports)](https://img.shields.io/bundlejs/size/iron-session?exports=getIronSession)

<p align="center">Online demo: <a href="https://get-iron-session.vercel.app/">https://get-iron-session.vercel.app</a> 👀</p>
**`iron-session` is a secure, stateless, and cookie-based session library for JavaScript.**

The session data is stored in signed and encrypted cookies which are decoded by your server code in a stateless fashion (= no network involved). This is the same technique used by frameworks like
[Ruby On Rails](https://guides.rubyonrails.org/security.html#session-storage).

<p align="center"><i>⭐️ Featured in the <a href="https://nextjs.org/docs/authentication">Next.js documentation</a></i></p>
<p align="center"><i>Online demo and examples: <a href="https://get-iron-session.vercel.app/">https://get-iron-session.vercel.app</a></i> 👀 <br/>
<i>Featured in the <a href="https://nextjs.org/docs/authentication">Next.js documentation</a></i> ⭐️</p>

## Table of Contents

Expand Down Expand Up @@ -145,7 +146,7 @@ await session.save()
Destroys the session. This is a synchronous operation as it only removes the cookie. It must be done before headers are sent to the client.

```ts
await session.destroy()
session.destroy()
```

### `sealData(data: unknown, { password, ttl }): Promise<string>`
Expand Down
2 changes: 1 addition & 1 deletion examples/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
"eslint-config-next": "14.0.3",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"typescript": "^5"
"typescript": "^5.3.2"
}
}
Binary file added examples/next/public/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/next/public/github-mark-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions examples/next/src/app/GitHubLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Image from "next/image";

export default function GitHubLogo() {
return (
<>
<Image
src="/github-mark.svg"
alt="GitHub Logo"
width={20}
height={20}
className="dark:hidden"
/>
<Image
src="/github-mark-white.svg"
alt="GitHub Logo"
width={20}
height={20}
className="hidden dark:block"
/>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function LoginForm() {
className={css.form}
>
<label className="block text-lg">
<span className="text-gray-700">Username</span>
<span className={css.label}>Username</span>
<input
type="text"
name="username"
Expand All @@ -69,7 +69,7 @@ function LogoutButton() {
return (
<p>
<a
href="/app-router-client-component-redirect-route-handler-fetch/logout"
href="/app-router-client-component-redirect-route-handler-fetch/session?action=logout"
className={css.button}
>
Logout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as css from "@/app/css";
import { Metadata } from "next";
import { Form } from "./form";
import { Title } from "../title";
import { GetTheCode } from "../get-the-code";
import { GetTheCode } from "../../get-the-code";

export const metadata: Metadata = {
title:
Expand All @@ -21,7 +21,7 @@ export default function AppRouterRedirect() {
action.
</p>

<div className="grid grid-cols-1 gap-4 p-10 border border-gray-500 rounded-md max-w-xl">
<div className="grid grid-cols-1 gap-4 p-10 border border-slate-500 rounded-md max-w-xl">
<Form />
</div>

Expand All @@ -40,20 +40,21 @@ export default function AppRouterRedirect() {
function HowItWorks() {
return (
<details className="max-w-2xl space-y-4">
<summary className="cursor-pointer text-gray-700">How it works</summary>
<summary className="cursor-pointer">How it works</summary>

<ol className="list-decimal list-inside">
<li>
The form is submitted to
/app-router-client-component-redirect-route-handler-fetch/session
(route handler) via a POST call (non-fetch). The route handler sets
the session data and redirects back to /app-router (this page).
/app-router-client-component-redirect-route-handler-fetch/session (API
route) via a POST call (non-fetch). The API route sets the session
data and redirects back to
/app-router-client-component-redirect-route-handler-fetch (this page).
</li>
<li>
The page gets the session data via a fetch call to
/app-router-client-component-redirect-route-handler-fetch/session
(route handler). The route handler either return the session data
(logged in) or a default session (not logged in).
/app-router-client-component-redirect-route-handler-fetch/session (API
route). The API route either return the session data (logged in) or a
default session (not logged in).
</li>
<li>
The logout is a regular link navigating to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@ import { redirect } from "next/navigation";
import { sleep, SessionData } from "../lib";

// /app-router-client-component-redirect-route-handler-fetch/session
export async function POST(
request: NextRequest,
{ params }: { params: { action: string } },
) {
if (params.action !== "session") {
return new Response("Unknown path", { status: 404 });
}

export async function POST(request: NextRequest) {
const session = await getIronSession<SessionData>(cookies(), sessionOptions);

const formData = await request.formData();
Expand All @@ -34,20 +27,15 @@ export async function POST(
}

// /app-router-client-component-redirect-route-handler-fetch/session
// /app-router-client-component-redirect-route-handler-fetch/logout
export async function GET(
_request: NextRequest,
{ params }: { params: { action: string } },
) {
if (params.action !== "session" && params.action !== "logout") {
return new Response("Unknown path", { status: 404 });
}

// /app-router-client-component-redirect-route-handler-fetch/session?action=logout
export async function GET(request: NextRequest) {
const session = await getIronSession<SessionData>(cookies(), sessionOptions);

// /app-router-client-component-redirect-route-handler-fetch/logout
if (params.action === "logout") {
await session.destroy();
console.log(new URL(request.url).searchParams);
const action = new URL(request.url).searchParams.get("action");
// /app-router-client-component-redirect-route-handler-fetch/session?action=logout
if (action === "logout") {
session.destroy();
return redirect(
"/app-router-client-component-redirect-route-handler-fetch",
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function LoginForm() {
className={css.form}
>
<label className="block text-lg">
<span className="text-gray-700">Username</span>
<span className={css.label}>Username</span>
<input
type="text"
name="username"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import * as css from "@/app/css";
import { Metadata } from "next";
import { Form } from "./form";
import { Title } from "@/app/title";
import { GetTheCode } from "../get-the-code";
import { GetTheCode } from "../../get-the-code";

export const metadata: Metadata = {
title: "🛠 iron-session examples: Client components, route handlers and SWR",
};

export default function AppRouterRedirect() {
export default function AppRouterSWR() {
return (
<main className="p-10 space-y-5">
<Title
Expand All @@ -34,9 +34,9 @@ export default function AppRouterRedirect() {
SWR automatically.
</p>

<div className="grid grid-cols-1 gap-4 p-10 border border-gray-500 rounded-md max-w-xl">
<div className="grid grid-cols-1 gap-4 p-10 border border-slate-500 rounded-md max-w-xl">
<Form />
<div className="text-gray-700 space-y-2">
<div className="space-y-2">
<hr />
<p>
The following pages are protected and will redirect back here if
Expand Down Expand Up @@ -91,7 +91,7 @@ export default function AppRouterRedirect() {
function HowItWorks() {
return (
<details className="max-w-2xl space-y-4">
<summary className="cursor-pointer text-gray-700">How it works</summary>
<summary className="cursor-pointer">How it works</summary>

<ol className="list-decimal list-inside">
<li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function Content() {
This page is protected and can only be accessed if you are logged in.
Otherwise you will be redirected to the login page.
</p>
<p>The check is done via a fetch call on the client.</p>
<p>The check is done via a fetch call on the client using SWR.</p>
<p>
One benefit of using{" "}
<a href="https://swr.vercel.app" target="_blank" className={css.link}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ export async function GET() {
export async function DELETE() {
const session = await getIronSession<SessionData>(cookies(), sessionOptions);

// /app-router-client-component-route-handler-swr/logout
await session.destroy();
session.destroy();

return Response.json(defaultSession);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function logout() {

// false => no db call for logout
const session = await getSession(false);
await session.destroy();
session.destroy();
revalidatePath("/app-router-server-component-and-action");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function LoginForm() {
return (
<form action={login} className={css.form}>
<label className="block text-lg">
<span className="text-gray-700">Username</span>
<span className={css.label}>Username</span>
<Input />
</label>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Form } from "./form";
import { Suspense } from "react";
import * as css from "@/app/css";
import { Title } from "../title";
import { GetTheCode } from "../get-the-code";
import { GetTheCode } from "../../get-the-code";

export const metadata: Metadata = {
title: "🛠 iron-session examples: Server components, and server actions",
Expand All @@ -21,7 +21,7 @@ export default async function AppRouter() {
action.
</p>

<div className="grid grid-cols-1 gap-4 p-10 border border-gray-500 rounded-md max-w-xl">
<div className="grid grid-cols-1 gap-4 p-10 border border-slate-500 rounded-md max-w-xl">
<Suspense fallback={<p className="text-lg">Loading...</p>}>
<Form />
</Suspense>
Expand All @@ -42,7 +42,7 @@ export default async function AppRouter() {
function HowItWorks() {
return (
<details className="max-w-2xl space-y-4">
<summary className="cursor-pointer text-gray-700">How it works</summary>
<summary className="cursor-pointer">How it works</summary>

<ol className="list-decimal list-inside">
<li>During login, the page uses a server action.</li>
Expand Down
9 changes: 6 additions & 3 deletions examples/next/src/app/css.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
export const button =
"hover:bg-gray-200 text-black border border-black py-2 px-4 rounded focus:outline-2 cursor-pointer";
"hover:bg-slate-200 dark:hover:bg-slate-600 text-slate-900 dark:text-white border border-text-slate-900 dark:border-text-white py-2 px-4 rounded focus:outline-2 cursor-pointer";

export const form = "max-w-md grid grid-cols-1 gap-6";

export const label = "text-slate-700 dark:text-slate-300";

export const input =
"mt-1 block w-full disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500";
"mt-1 block w-full disabled:cursor-not-allowed disabled:bg-slate-50 disabled:text-slate-500 dark:text-slate-900";

export const link = "text-indigo-500 underline hover:no-underline";
export const link =
"text-indigo-500 dark:text-indigo-400 underline hover:no-underline";
2 changes: 1 addition & 1 deletion examples/next/src/app/fathom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function TrackPageView() {
if (!pathname) return;

trackPageview({
url: pathname + searchParams.toString(),
url: pathname + searchParams?.toString() ?? "",
referrer: document.referrer,
});
}, [pathname, searchParams]);
Expand Down
4 changes: 4 additions & 0 deletions examples/next/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
@apply bg-slate-50 dark:bg-slate-800 text-slate-900 dark:text-white;
}
2 changes: 1 addition & 1 deletion examples/next/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className={`${inter.className} bg-gray-50`}>
<body className={inter.className}>
<Fathom />
{children}
</body>
Expand Down
Loading