Skip to content

Commit

Permalink
chore: polish app router example
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-jonas committed Dec 13, 2024
1 parent 33747d4 commit 641a6e9
Show file tree
Hide file tree
Showing 12 changed files with 221 additions and 82 deletions.
2 changes: 1 addition & 1 deletion examples/nextjs-app-router/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
font-family: Inter, Helvetica, sans-serif;
}

@layer utilities {
Expand Down
7 changes: 5 additions & 2 deletions examples/nextjs-app-router/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

import "./globals.css"
import React, { Suspense, ReactNode } from "react"
import { Inter } from "next/font/google"

const inter = Inter({ subsets: ["latin"] })

export default function RootLayout({
children,
}: Readonly<{
children: ReactNode
}>) {
return (
<html lang="en">
<body className={`antialiased overflow-hidden`}>
<html lang="en" suppressHydrationWarning className={inter.className}>
<body>
<Suspense>{children}</Suspense>
</body>
</html>
Expand Down
8 changes: 8 additions & 0 deletions examples/nextjs-app-router/app/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 85 additions & 11 deletions examples/nextjs-app-router/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,93 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0

"use client"
import { useSession } from "@ory/elements-react/client"
import { SessionProvider } from "@ory/elements-react/client"
import { getLogoutFlow, getServerSession } from "@ory/nextjs/app"
import { Metadata } from "next"
import Image from "next/image"
import Link from "next/link"
import OryLogo from "./logo.svg"

export const metadata: Metadata = {
title: "Ory Next.js App router Example",
}

export default async function RootLayout() {
const session = await getServerSession()

return (
<SessionProvider session={session}>
<div className="flex items-center justify-center min-h-screen bg-gray-50">
<div className="flex flex-col items-center gap-4">
<Image src={OryLogo} alt="Ory Logo" width={160} />
<h1 className="font-bold text-xl">Ory Next.js App Router Example</h1>
{!session && (
<div className="flex items-center gap-2 bg-white rounded border flex-col w-60 p-3">
<Link
className="underline block w-full"
href="/auth/registration"
>
Registration
</Link>
<Link className="underline block w-full" href="/auth/login">
Login
</Link>
<Link className="underline block w-full" href="/auth/recovery">
Account Recovery
</Link>
<Link
className="underline block w-full"
href="/auth/verification"
>
Account Verification
</Link>
</div>
)}
{session && (
<div className="flex items-center gap-2 bg-white rounded border flex-col w-60 p-3">
<h2 className="w-full">
Hi,{" "}
{session.identity?.traits.email ??
session.identity?.traits.username ??
session.identity?.traits.phone}
!
</h2>
<Link className="underline block w-full" href="/settings">
Settings
</Link>
<LogoutLink />
</div>
)}
<div className="flex gap-2 text-sm">
<a
href="https://github.com/ory/elements/tree/master/examples/nextjs-pages-router"
className="underline"
target="_blank"
rel="noreferrer"
>
App Router Example
</a>
<a
href="https://github.com/ory/elements/tree/master/examples/nextjs-pages-router"
className="underline"
target="_blank"
rel="noreferrer"
>
Page Router Example
</a>
</div>
</div>
</div>
</SessionProvider>
)
}

async function LogoutLink() {
const flow = await getLogoutFlow({})

export default function RootLayout() {
const { session } = useSession()
if (session) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return "Hello: " + session.identity?.traits.email
}
return (
<p>
Not authenticated, please <Link href={"/auth/login"}>log in</Link>.
</p>
<Link className="underline block w-full" href={flow.logout_url}>
Logout
</Link>
)
}
32 changes: 32 additions & 0 deletions examples/nextjs-app-router/app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0

import { Settings } from "@ory/elements-react/theme"
import { SessionProvider } from "@ory/elements-react/client"
import { enhanceOryConfig } from "@ory/nextjs"
import { getSettingsFlow, OryPageParams } from "@ory/nextjs/app"
import "@ory/elements-react/theme/styles.css"

import config from "@/ory.config"

export default async function SettingsPage(props: OryPageParams) {
const flow = await getSettingsFlow(props.searchParams)

if (!flow) {
return null
}

return (
<div className="flex flex-col gap-8 items-center mb-8">
<SessionProvider>
<Settings
flow={flow}
config={enhanceOryConfig(config)}
components={{
Card: {},
}}
/>
</SessionProvider>
</div>
)
}
4 changes: 3 additions & 1 deletion examples/nextjs-app-router/ory.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import type { OryConfig } from "@ory/nextjs"

const config: OryConfig = {
override: {
applicationName: "NextJS app router example",
applicationName: "Ory Next.js App Router Example",
loginUiPath: "/auth/login",
registrationUiPath: "/auth/registration",
recoveryUiPath: "/auth/recovery",
verificationUiPath: "/auth/verification",
settingsUiPath: "/settings",
defaultRedirectUri: "/",
},
}

Expand Down
68 changes: 17 additions & 51 deletions examples/nextjs-pages-router/README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,22 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with
[`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
This is a simple example application using @ory/elements-react & Next.js app
router.

## Getting Started
## Getting started

First, run the development server:
1. Sign up for an account at https://console.ory.sh
2. Create a new or use an existing project
3. Go to https://console.ory.sh/projects/current/settings and copy the **API
endpoints** URL
4. Set the `NEXT_PUBLIC_ORY_SDK_URL` to your project's **API endpoints** URL
5. Run `npm install`
6. Run `npm run dev` and open navigate to https://localhost:3000

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
> [!WARNING] For convinience Ory provides a default "playground" project, that
> can be used to interact with Ory's APIs. It is a public project, that can be
> used by anyone and data can be deleted at any time. Make sure to use a
> dedicated project.
Open [http://localhost:3000](http://localhost:3000) with your browser to see the
result.
## Need help?

You can start editing the page by modifying `pages/index.tsx`. The page
auto-updates as you edit the file.

[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on
[http://localhost:3000/api/hello](http://localhost:3000/api/hello). This
endpoint can be edited in `pages/api/hello.ts`.

The `pages/api` directory is mapped to `/api/*`. Files in this directory are
treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead
of React pages.

This project uses
[`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to
automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js
features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out
[the Next.js GitHub repository](https://github.com/vercel/next.js/) - your
feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the
[Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme)
from the creators of Next.js.

Check out our
[Next.js deployment documentation](https://nextjs.org/docs/deployment) for more
details.
If you have any issues using this examples, or Ory's products, don't hesitate to
reach out via the [Ory Community Slack](https://slack.ory.sh).
16 changes: 0 additions & 16 deletions examples/nextjs-pages-router/pages/api/hello.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/nextjs/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { getRegistrationFlow } from "./registration"
export { getRecoveryFlow } from "./recovery"
export { getVerificationFlow } from "./verification"
export { getSettingsFlow } from "./settings"
export { getLogoutFlow } from "./logout"
export { getServerSession } from "./session"

export type { OryPageParams } from "./utils"
46 changes: 46 additions & 0 deletions packages/nextjs/src/app/logout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
import { LogoutFlow } from "@ory/client-fetch"

import { headers } from "next/headers"
import { rewriteJsonResponse } from "../utils/rewrite"
import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
import { serverSideFrontendClient } from "./client"
import { getPublicUrl } from "./utils"

/**
* Use this method in an app router page to create a new logout flow. This method works with server-side rendering.
*
* ```
* import { getLogoutFlow } from "@ory/nextjs/app"
*
* async function LogoutLink() {
* const flow = await getLogoutFlow()
*
* return (
* <a href={flow.logout_url}>
* Logout
* </a>
* )
* }
*
* ```
*
* @param params - The query parameters of the request.
*/
export async function getLogoutFlow({
returnTo,
}: { returnTo?: string } = {}): Promise<LogoutFlow> {
const h = await headers()

const knownProxiedUrl = await getPublicUrl()
const url = guessPotentiallyProxiedOrySdkUrl({
knownProxiedUrl,
})
return serverSideFrontendClient
.createBrowserLogoutFlow({
cookie: h.get("cookie") ?? "",
returnTo,
})
.then((v: LogoutFlow): LogoutFlow => rewriteJsonResponse(v, url))
}
20 changes: 20 additions & 0 deletions packages/nextjs/src/middleware/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const createOptions = (): OryConfig => ({
forwardAdditionalHeaders: ["x-custom-header"],
override: {
loginUiPath: "/custom-login",
defaultRedirectUri: "/custom-redirect",
},
})

Expand Down Expand Up @@ -175,6 +176,25 @@ describe("proxyRequest", () => {
expect(response?.status).toBe(302)
})

it("modifies relative location header for redirects", async () => {
const request = createMockLoginRequest()
const upstreamResponseHeaders = new Headers({
location: "/ui/welcome",
})

mockFetch({
headers: upstreamResponseHeaders,
status: 302,
})

const response = await proxyRequest(request, createOptions())

expect(response?.headers.get("location")).toBe(
"http://localhost/custom-redirect",
)
expect(response?.status).toBe(302)
})

const createTestCase = (
part: "login" | "registration" | "recovery" | "verification" | "settings",
) => ({
Expand Down
3 changes: 3 additions & 0 deletions packages/nextjs/src/middleware/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ export async function proxyRequest(request: NextRequest, options: OryConfig) {
// This is not needed with the "new" account experience based on this SDK.
if (location.startsWith("../self-service")) {
location = location.replace("../self-service", "/self-service")
} else if (!location.startsWith("http")) {
// If the location header is not an absolute URL, we need to make it one for rewriteUrls to properly rewrite it.
location = new URL(location, matchBaseUrl).toString()
}

location = rewriteUrls(location, matchBaseUrl.toString(), selfUrl, options)
Expand Down

0 comments on commit 641a6e9

Please sign in to comment.