From c0e31a716eb11066816e305f4e417745dc2017df Mon Sep 17 00:00:00 2001
From: aeneasr <3372410+aeneasr@users.noreply.github.com>
Date: Fri, 15 Nov 2024 16:37:45 +0100
Subject: [PATCH] chore: synchronize workspaces
---
.../nextjs-app-router/app/auth/login/page.tsx | 6 +-
.../app/auth/recovery/page.tsx | 29 +++++
.../app/auth/registration/page.tsx | 27 ++++
.../app/auth/verification/page.tsx | 29 +++++
.../custom-card-header.tsx} | 2 +-
examples/nextjs-app-router/ory.config.ts | 3 +
examples/nextjs-pages-router/ory.config.ts | 3 +
.../nextjs-pages-router/pages/auth/login.tsx | 29 +++++
.../pages/auth/recovery.tsx | 29 +++++
.../pages/auth/verification.tsx | 29 +++++
packages/nextjs/src/app/flow.ts | 64 ++++++++++
packages/nextjs/src/app/index.ts | 4 +
packages/nextjs/src/app/login.ts | 96 ++++----------
packages/nextjs/src/app/recovery.ts | 53 ++++++++
packages/nextjs/src/app/registration.ts | 53 ++++++++
packages/nextjs/src/app/verification.ts | 53 ++++++++
packages/nextjs/src/pages/client.ts | 21 +--
packages/nextjs/src/pages/flow.ts | 65 ++++++++++
packages/nextjs/src/pages/index.ts | 3 +
packages/nextjs/src/pages/login.ts | 22 ++++
packages/nextjs/src/pages/recovery.ts | 16 +++
packages/nextjs/src/pages/registration.ts | 120 +++---------------
packages/nextjs/src/pages/utils.ts | 36 ++++++
packages/nextjs/src/pages/verification.ts | 16 +++
packages/nextjs/src/utils/utils.ts | 8 ++
25 files changed, 626 insertions(+), 190 deletions(-)
create mode 100644 examples/nextjs-app-router/app/auth/recovery/page.tsx
create mode 100644 examples/nextjs-app-router/app/auth/registration/page.tsx
create mode 100644 examples/nextjs-app-router/app/auth/verification/page.tsx
rename examples/nextjs-app-router/{app/auth/login/card-header.tsx => components/custom-card-header.tsx} (73%)
create mode 100644 examples/nextjs-pages-router/pages/auth/login.tsx
create mode 100644 examples/nextjs-pages-router/pages/auth/recovery.tsx
create mode 100644 examples/nextjs-pages-router/pages/auth/verification.tsx
create mode 100644 packages/nextjs/src/app/flow.ts
create mode 100644 packages/nextjs/src/app/recovery.ts
create mode 100644 packages/nextjs/src/app/registration.ts
create mode 100644 packages/nextjs/src/app/verification.ts
create mode 100644 packages/nextjs/src/pages/flow.ts
create mode 100644 packages/nextjs/src/pages/login.ts
create mode 100644 packages/nextjs/src/pages/recovery.ts
create mode 100644 packages/nextjs/src/pages/verification.ts
diff --git a/examples/nextjs-app-router/app/auth/login/page.tsx b/examples/nextjs-app-router/app/auth/login/page.tsx
index f8d6479a4..eceeaaccc 100644
--- a/examples/nextjs-app-router/app/auth/login/page.tsx
+++ b/examples/nextjs-app-router/app/auth/login/page.tsx
@@ -6,7 +6,7 @@ import { getLoginFlow, OryPageParams } from "@ory/nextjs/app"
import { enhanceConfig } from "@ory/nextjs"
import config from "@/ory.config"
-import CardHeader from "@/app/auth/login/card-header"
+import CustomCardHeader from "@/components/custom-card-header"
export default async function LoginPage(props: OryPageParams) {
const flow = await getLoginFlow(props.searchParams)
@@ -20,9 +20,7 @@ export default async function LoginPage(props: OryPageParams) {
flow={flow}
config={enhanceConfig(config)}
components={{
- Card: {
- Header: CardHeader,
- },
+ Card: {},
}}
/>
)
diff --git a/examples/nextjs-app-router/app/auth/recovery/page.tsx b/examples/nextjs-app-router/app/auth/recovery/page.tsx
new file mode 100644
index 000000000..67718d65e
--- /dev/null
+++ b/examples/nextjs-app-router/app/auth/recovery/page.tsx
@@ -0,0 +1,29 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { Recovery } from "@ory/elements-react/theme"
+import { getRecoveryFlow, OryPageParams } from "@ory/nextjs/app"
+import { enhanceConfig } from "@ory/nextjs"
+
+import config from "@/ory.config"
+import CustomCardHeader from "@/components/custom-card-header"
+
+export default async function RecoveryPage(props: OryPageParams) {
+ const flow = await getRecoveryFlow(props.searchParams)
+
+ if (!flow) {
+ return null
+ }
+
+ return (
+
+ )
+}
diff --git a/examples/nextjs-app-router/app/auth/registration/page.tsx b/examples/nextjs-app-router/app/auth/registration/page.tsx
new file mode 100644
index 000000000..bfbf218ae
--- /dev/null
+++ b/examples/nextjs-app-router/app/auth/registration/page.tsx
@@ -0,0 +1,27 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { Registration } from "@ory/elements-react/theme"
+import { getRegistrationFlow, OryPageParams } from "@ory/nextjs/app"
+import { enhanceConfig } from "@ory/nextjs"
+
+import config from "@/ory.config"
+import CustomCardHeader from "@/components/custom-card-header"
+
+export default async function RegistrationPage(props: OryPageParams) {
+ const flow = await getRegistrationFlow(props.searchParams)
+
+ if (!flow) {
+ return null
+ }
+
+ return (
+
+ )
+}
diff --git a/examples/nextjs-app-router/app/auth/verification/page.tsx b/examples/nextjs-app-router/app/auth/verification/page.tsx
new file mode 100644
index 000000000..057303455
--- /dev/null
+++ b/examples/nextjs-app-router/app/auth/verification/page.tsx
@@ -0,0 +1,29 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { Verification } from "@ory/elements-react/theme"
+import { getVerificationFlow, OryPageParams } from "@ory/nextjs/app"
+import { enhanceConfig } from "@ory/nextjs"
+
+import config from "@/ory.config"
+import CustomCardHeader from "@/components/custom-card-header"
+
+export default async function VerificationPage(props: OryPageParams) {
+ const flow = await getVerificationFlow(props.searchParams)
+
+ if (!flow) {
+ return null
+ }
+
+ return (
+
+ )
+}
diff --git a/examples/nextjs-app-router/app/auth/login/card-header.tsx b/examples/nextjs-app-router/components/custom-card-header.tsx
similarity index 73%
rename from examples/nextjs-app-router/app/auth/login/card-header.tsx
rename to examples/nextjs-app-router/components/custom-card-header.tsx
index f6ea27eeb..31683ac6a 100644
--- a/examples/nextjs-app-router/app/auth/login/card-header.tsx
+++ b/examples/nextjs-app-router/components/custom-card-header.tsx
@@ -3,6 +3,6 @@
"use client"
-export default function CardHeader() {
+export default function CustomCardHeader() {
return
My custom card header
}
diff --git a/examples/nextjs-app-router/ory.config.ts b/examples/nextjs-app-router/ory.config.ts
index d07568cbf..30dbd2fd2 100644
--- a/examples/nextjs-app-router/ory.config.ts
+++ b/examples/nextjs-app-router/ory.config.ts
@@ -7,6 +7,9 @@ const config: OryConfig = {
override: {
applicationName: "NextJS app router example",
loginUiPath: "/auth/login",
+ registrationUiPath: "/auth/registration",
+ recoveryUiPath: "/auth/recovery",
+ verificationUiPath: "/auth/verification",
},
}
diff --git a/examples/nextjs-pages-router/ory.config.ts b/examples/nextjs-pages-router/ory.config.ts
index 7130533dd..8ec4d57f1 100644
--- a/examples/nextjs-pages-router/ory.config.ts
+++ b/examples/nextjs-pages-router/ory.config.ts
@@ -6,7 +6,10 @@ import type { OryConfig } from "@ory/nextjs"
const config: OryConfig = {
override: {
applicationName: "NextJS pages router example",
+ loginUiPath: "/auth/login",
registrationUiPath: "/auth/registration",
+ recoveryUiPath: "/auth/recovery",
+ verificationUiPath: "/auth/verification",
},
}
diff --git a/examples/nextjs-pages-router/pages/auth/login.tsx b/examples/nextjs-pages-router/pages/auth/login.tsx
new file mode 100644
index 000000000..40cf6f60b
--- /dev/null
+++ b/examples/nextjs-pages-router/pages/auth/login.tsx
@@ -0,0 +1,29 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+"use client"
+import { Login } from "@ory/elements-react/theme"
+import { useLoginFlow } from "@ory/nextjs/pages"
+import { enhanceConfig } from "@ory/nextjs"
+import "@ory/elements-react/theme/styles.css"
+
+import config from "@/ory.config"
+
+export default function LoginPage() {
+ const flow = useLoginFlow()
+
+ if (!flow) {
+ return null
+ }
+
+ return (
+
+
+
+ )
+}
diff --git a/examples/nextjs-pages-router/pages/auth/recovery.tsx b/examples/nextjs-pages-router/pages/auth/recovery.tsx
new file mode 100644
index 000000000..315e8d066
--- /dev/null
+++ b/examples/nextjs-pages-router/pages/auth/recovery.tsx
@@ -0,0 +1,29 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+"use client"
+import { Recovery } from "@ory/elements-react/theme"
+import { useRecoveryFlow } from "@ory/nextjs/pages"
+import { enhanceConfig } from "@ory/nextjs"
+import "@ory/elements-react/theme/styles.css"
+
+import config from "@/ory.config"
+
+export default function RecoveryPage() {
+ const flow = useRecoveryFlow()
+
+ if (!flow) {
+ return null
+ }
+
+ return (
+
+
+
+ )
+}
diff --git a/examples/nextjs-pages-router/pages/auth/verification.tsx b/examples/nextjs-pages-router/pages/auth/verification.tsx
new file mode 100644
index 000000000..1b9837f3f
--- /dev/null
+++ b/examples/nextjs-pages-router/pages/auth/verification.tsx
@@ -0,0 +1,29 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+"use client"
+import { Verification } from "@ory/elements-react/theme"
+import { useVerificationFlow } from "@ory/nextjs/pages"
+import { enhanceConfig } from "@ory/nextjs"
+import "@ory/elements-react/theme/styles.css"
+
+import config from "@/ory.config"
+
+export default function VerificationPage() {
+ const flow = useVerificationFlow()
+
+ if (!flow) {
+ return null
+ }
+
+ return (
+
+
+
+ )
+}
diff --git a/packages/nextjs/src/app/flow.ts b/packages/nextjs/src/app/flow.ts
new file mode 100644
index 000000000..08a64411c
--- /dev/null
+++ b/packages/nextjs/src/app/flow.ts
@@ -0,0 +1,64 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { redirect, RedirectType } from "next/navigation"
+import { FlowType, handleFlowError } from "@ory/client-fetch"
+
+import { getPublicUrl, onRedirect } from "./utils"
+import { QueryParams } from "../types"
+import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
+import { onValidationError } from "../utils/utils"
+import { rewriteJsonResponse } from "../utils/rewrite"
+import * as runtime from "@ory/client-fetch/src/runtime"
+
+export async function getFlow(
+ params: QueryParams | Promise,
+ fetchFlowRaw: () => Promise>,
+ flowType: FlowType,
+): Promise {
+ const p = await params
+
+ // Guess our own public url using Next.js helpers. We need the hostname, port, and protocol.
+ const knownProxiedUrl = await getPublicUrl()
+
+ const onRestartFlow = () => {
+ return redirect(
+ new URL(
+ "/self-service/" +
+ flowType.toString() +
+ "/browser?" +
+ params.toString(),
+ guessPotentiallyProxiedOrySdkUrl({
+ knownProxiedUrl,
+ }),
+ ).toString(),
+ RedirectType.replace,
+ )
+ }
+
+ if (!p["flow"]) {
+ onRestartFlow()
+ return
+ }
+
+ try {
+ const rawResponse = await fetchFlowRaw()
+ return await rawResponse
+ .value()
+ .then(
+ (v: T): T =>
+ rewriteJsonResponse(
+ v,
+ guessPotentiallyProxiedOrySdkUrl({ knownProxiedUrl }),
+ ),
+ )
+ } catch (error) {
+ const errorHandler = handleFlowError({
+ onValidationError,
+ onRestartFlow,
+ onRedirect: onRedirect,
+ })
+ await errorHandler(error)
+ return null
+ }
+}
diff --git a/packages/nextjs/src/app/index.ts b/packages/nextjs/src/app/index.ts
index b233b6e63..18e19f5bd 100644
--- a/packages/nextjs/src/app/index.ts
+++ b/packages/nextjs/src/app/index.ts
@@ -3,4 +3,8 @@
"use server"
export { getLoginFlow } from "./login"
+export { getRegistrationFlow } from "./registration"
+export { getRecoveryFlow } from "./recovery"
+export { getVerificationFlow } from "./verification"
+
export type { OryPageParams } from "./utils"
diff --git a/packages/nextjs/src/app/login.ts b/packages/nextjs/src/app/login.ts
index 5bc317c04..34b8451ec 100644
--- a/packages/nextjs/src/app/login.ts
+++ b/packages/nextjs/src/app/login.ts
@@ -1,42 +1,38 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
-import { redirect, RedirectType } from "next/navigation"
-import { FlowType, handleFlowError, LoginFlow } from "@ory/client-fetch"
+import { FlowType, LoginFlow } from "@ory/client-fetch"
-import { getPublicUrl, onRedirect } from "./utils"
import { initOverrides, QueryParams } from "../types"
-import { toFlowParams } from "./utils"
-import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
-import { onValidationError } from "../utils/utils"
-import { rewriteJsonResponse } from "../utils/rewrite"
import { serverSideFrontendClient } from "./client"
-
-// const factory = getFlowFactory({
-// redirectToBrowserEndpoint,
-// onRedirect,
-// toFlowParams,
-// flowType: FlowType.Login,
-// fetchFlow: newOryFrontendClient().getLoginFlowRaw,
-// })
+import { getFlow } from "./flow"
+import { toFlowParams } from "./utils"
/**
* Use this method in an app router page to fetch an existing login flow or to create a new one. This method works with server-side rendering.
*
* ```
- * import { useLoginFlow, newFrontendClient } from "@ory/nextjs"
- * import { Login } from "@ory/elements/headless/flows/login"
+ * import { Login } from "@ory/elements-react/theme"
+ * import { getLoginFlow, OryPageParams } from "@ory/nextjs/app"
+ * import { enhanceConfig } from "@ory/nextjs"
*
- * const client = newFrontendClient()
+ * import config from "@/ory.config"
+ * import CardHeader from "@/app/auth/login/card-header"
*
- * export default async function LoginPage({ searchParams }: PageProps) {
- * const flow = await useLoginFlow(searchParams, client)
+ * export default async function LoginPage(props: OryPageParams) {
+ * const flow = await getLoginFlow(props.searchParams)
+ *
+ * if (!flow) {
+ * return null
+ * }
*
* return (
*
* )
@@ -48,52 +44,10 @@ import { serverSideFrontendClient } from "./client"
export async function getLoginFlow(
params: QueryParams | Promise,
): Promise {
- const p = await params
-
- // Guess our own public url using Next.js helpers. We need the hostname, port, and protocol.
- const knownProxiedUrl = await getPublicUrl()
-
- const onRestartFlow = () => {
- return redirect(
- new URL(
- "/self-service/" +
- FlowType.Login.toString() +
- "/browser?" +
- params.toString(),
- guessPotentiallyProxiedOrySdkUrl({
- knownProxiedUrl,
- }),
- ).toString(),
- RedirectType.replace,
- )
- }
-
- if (!p["flow"]) {
- onRestartFlow()
- return
- }
-
- try {
- const resp = await serverSideFrontendClient.getLoginFlowRaw(
- await toFlowParams(p),
- initOverrides,
- )
-
- return await resp
- .value()
- .then((v) =>
- rewriteJsonResponse(
- v,
- guessPotentiallyProxiedOrySdkUrl({ knownProxiedUrl }),
- ),
- )
- } catch (error) {
- const errorHandler = handleFlowError({
- onValidationError,
- onRestartFlow,
- onRedirect: onRedirect,
- })
- await errorHandler(error)
- return null
- }
+ const p = await toFlowParams(await params)
+ return getFlow(
+ params,
+ () => serverSideFrontendClient.getLoginFlowRaw(p, initOverrides),
+ FlowType.Login,
+ )
}
diff --git a/packages/nextjs/src/app/recovery.ts b/packages/nextjs/src/app/recovery.ts
new file mode 100644
index 000000000..c25dd9026
--- /dev/null
+++ b/packages/nextjs/src/app/recovery.ts
@@ -0,0 +1,53 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+import { FlowType, RecoveryFlow } from "@ory/client-fetch"
+
+import { initOverrides, QueryParams } from "../types"
+import { serverSideFrontendClient } from "./client"
+import { getFlow } from "./flow"
+import { toFlowParams } from "./utils"
+
+/**
+ * Use this method in an app router page to fetch an existing recovery flow or to create a new one. This method works with server-side rendering.
+ *
+ * ```
+ * import { Recovery } from "@ory/elements-react/theme"
+ * import { getRecoveryFlow, OryPageParams } from "@ory/nextjs/app"
+ * import { enhanceConfig } from "@ory/nextjs"
+ *
+ * import config from "@/ory.config"
+ * import CardHeader from "@/app/auth/recovery/card-header"
+ *
+ * export default async function RecoveryPage(props: OryPageParams) {
+ * const flow = await getRecoveryFlow(props.searchParams)
+ *
+ * if (!flow) {
+ * return null
+ * }
+ *
+ * return (
+ *
+ * )
+ * }
+ * ```
+ *
+ * @param params The query parameters of the request.
+ */
+export async function getRecoveryFlow(
+ params: QueryParams | Promise,
+): Promise {
+ const p = await toFlowParams(await params)
+ return getFlow(
+ params,
+ () => serverSideFrontendClient.getRecoveryFlowRaw(p, initOverrides),
+ FlowType.Recovery,
+ )
+}
diff --git a/packages/nextjs/src/app/registration.ts b/packages/nextjs/src/app/registration.ts
new file mode 100644
index 000000000..f9f4337e0
--- /dev/null
+++ b/packages/nextjs/src/app/registration.ts
@@ -0,0 +1,53 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+import { FlowType, RegistrationFlow } from "@ory/client-fetch"
+
+import { initOverrides, QueryParams } from "../types"
+import { serverSideFrontendClient } from "./client"
+import { getFlow } from "./flow"
+import { toFlowParams } from "./utils"
+
+/**
+ * Use this method in an app router page to fetch an existing registration flow or to create a new one. This method works with server-side rendering.
+ *
+ * ```
+ * import { Registration } from "@ory/elements-react/theme"
+ * import { getRegistrationFlow, OryPageParams } from "@ory/nextjs/app"
+ * import { enhanceConfig } from "@ory/nextjs"
+ *
+ * import config from "@/ory.config"
+ * import CardHeader from "@/app/auth/registration/card-header"
+ *
+ * export default async function RegistrationPage(props: OryPageParams) {
+ * const flow = await getRegistrationFlow(props.searchParams)
+ *
+ * if (!flow) {
+ * return null
+ * }
+ *
+ * return (
+ *
+ * )
+ * }
+ * ```
+ *
+ * @param params The query parameters of the request.
+ */
+export async function getRegistrationFlow(
+ params: QueryParams | Promise,
+): Promise {
+ const p = await toFlowParams(await params)
+ return getFlow(
+ params,
+ () => serverSideFrontendClient.getRegistrationFlowRaw(p, initOverrides),
+ FlowType.Registration,
+ )
+}
diff --git a/packages/nextjs/src/app/verification.ts b/packages/nextjs/src/app/verification.ts
new file mode 100644
index 000000000..db007dc56
--- /dev/null
+++ b/packages/nextjs/src/app/verification.ts
@@ -0,0 +1,53 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+import { FlowType, VerificationFlow } from "@ory/client-fetch"
+
+import { initOverrides, QueryParams } from "../types"
+import { serverSideFrontendClient } from "./client"
+import { getFlow } from "./flow"
+import { toFlowParams } from "./utils"
+
+/**
+ * Use this method in an app router page to fetch an existing verification flow or to create a new one. This method works with server-side rendering.
+ *
+ * ```
+ * import { Verification } from "@ory/elements-react/theme"
+ * import { getVerificationFlow, OryPageParams } from "@ory/nextjs/app"
+ * import { enhanceConfig } from "@ory/nextjs"
+ *
+ * import config from "@/ory.config"
+ * import CardHeader from "@/app/auth/verification/card-header"
+ *
+ * export default async function VerificationPage(props: OryPageParams) {
+ * const flow = await getVerificationFlow(props.searchParams)
+ *
+ * if (!flow) {
+ * return null
+ * }
+ *
+ * return (
+ *
+ * )
+ * }
+ * ```
+ *
+ * @param params The query parameters of the request.
+ */
+export async function getVerificationFlow(
+ params: QueryParams | Promise,
+): Promise {
+ const p = await toFlowParams(await params)
+ return getFlow(
+ params,
+ () => serverSideFrontendClient.getVerificationFlowRaw(p, initOverrides),
+ FlowType.Verification,
+ )
+}
diff --git a/packages/nextjs/src/pages/client.ts b/packages/nextjs/src/pages/client.ts
index 74f70667f..9cc0359d9 100644
--- a/packages/nextjs/src/pages/client.ts
+++ b/packages/nextjs/src/pages/client.ts
@@ -4,12 +4,15 @@ import { Configuration, FrontendApi } from "@ory/client-fetch"
import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
-export const clientSideFrontendClient = new FrontendApi(
- new Configuration({
- headers: {
- Accept: "application/json",
- },
- credentials: "include",
- basePath: guessPotentiallyProxiedOrySdkUrl(),
- }),
-)
+export const clientSideFrontendClient = () =>
+ new FrontendApi(
+ new Configuration({
+ headers: {
+ Accept: "application/json",
+ },
+ credentials: "include",
+ basePath: guessPotentiallyProxiedOrySdkUrl({
+ knownProxiedUrl: window.location.origin,
+ }),
+ }),
+ )
diff --git a/packages/nextjs/src/pages/flow.ts b/packages/nextjs/src/pages/flow.ts
new file mode 100644
index 000000000..ebc27cb2c
--- /dev/null
+++ b/packages/nextjs/src/pages/flow.ts
@@ -0,0 +1,65 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { FlowType, handleFlowError } from "@ory/client-fetch"
+import { useEffect, useState } from "react"
+import { useRouter } from "next/router"
+import { useSearchParams } from "next/navigation"
+import { handleRestartFlow, onValidationError, useOnRedirect } from "./utils"
+import { toValue } from "../utils/utils"
+import * as runtime from "@ory/client-fetch/src/runtime"
+
+interface Flow {
+ id: string
+}
+
+export function createUseFlowFactory(
+ flowType: FlowType,
+ createFlow: (params: URLSearchParams) => Promise>,
+ getFlow: (id: string) => Promise>,
+): () => T | null | void {
+ return () => {
+ const [flow, setFlow] = useState()
+ const router = useRouter()
+ const searchParams = useSearchParams()
+ const onRestartFlow = handleRestartFlow(searchParams, flowType)
+ const onRedirect = useOnRedirect()
+
+ const errorHandler = handleFlowError({
+ onValidationError,
+ onRestartFlow,
+ onRedirect,
+ })
+
+ const handleSetFlow = async (flow: T) => {
+ setFlow(flow)
+
+ // Use the router to update the `flow` search parameter only
+ await router.replace({
+ query: { flow: flow.id },
+ })
+ return
+ }
+
+ useEffect(() => {
+ const id = searchParams.get("flow")
+
+ // If the router is not ready yet, or we already have a flow, do nothing.
+ if (!router.isReady || flow !== undefined) {
+ return
+ }
+
+ if (!id) {
+ createFlow(searchParams)
+ .then(toValue)
+ .then(handleSetFlow)
+ .catch(errorHandler)
+ return
+ }
+
+ getFlow(id).then(toValue).then(handleSetFlow).catch(errorHandler)
+ }, [searchParams, router, router.isReady, flow])
+
+ return flow
+ }
+}
diff --git a/packages/nextjs/src/pages/index.ts b/packages/nextjs/src/pages/index.ts
index 2e705f95f..e2a8c6aeb 100644
--- a/packages/nextjs/src/pages/index.ts
+++ b/packages/nextjs/src/pages/index.ts
@@ -3,3 +3,6 @@
"use client"
export { useRegistrationFlow } from "./registration"
+export { useVerificationFlow } from "./verification"
+export { useRecoveryFlow } from "./recovery"
+export { useLoginFlow } from "./login"
diff --git a/packages/nextjs/src/pages/login.ts b/packages/nextjs/src/pages/login.ts
new file mode 100644
index 000000000..4a848a23a
--- /dev/null
+++ b/packages/nextjs/src/pages/login.ts
@@ -0,0 +1,22 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { clientSideFrontendClient } from "./client"
+import { createUseFlowFactory } from "./flow"
+import { FlowType } from "@ory/client-fetch"
+
+export const useLoginFlow = createUseFlowFactory(
+ FlowType.Login,
+ (params: URLSearchParams) => {
+ return clientSideFrontendClient().createBrowserLoginFlowRaw({
+ refresh: params.get("refresh") === "true",
+ aal: params.get("aal") ?? undefined,
+ returnTo: params.get("return_to") ?? undefined,
+ cookie: params.get("cookie") ?? undefined,
+ loginChallenge: params.get("login_challenge") ?? undefined,
+ organization: params.get("organization") ?? undefined,
+ via: params.get("via") ?? undefined,
+ })
+ },
+ (id) => clientSideFrontendClient().getLoginFlowRaw({ id }),
+)
diff --git a/packages/nextjs/src/pages/recovery.ts b/packages/nextjs/src/pages/recovery.ts
new file mode 100644
index 000000000..81671580d
--- /dev/null
+++ b/packages/nextjs/src/pages/recovery.ts
@@ -0,0 +1,16 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { clientSideFrontendClient } from "./client"
+import { createUseFlowFactory } from "./flow"
+import { FlowType } from "@ory/client-fetch"
+
+export const useRecoveryFlow = createUseFlowFactory(
+ FlowType.Recovery,
+ (params: URLSearchParams) => {
+ return clientSideFrontendClient().createBrowserRecoveryFlowRaw({
+ returnTo: params.get("return_to") ?? undefined,
+ })
+ },
+ (id) => clientSideFrontendClient().getRecoveryFlowRaw({ id }),
+)
diff --git a/packages/nextjs/src/pages/registration.ts b/packages/nextjs/src/pages/registration.ts
index fedede0c2..1d3d9c4c3 100644
--- a/packages/nextjs/src/pages/registration.ts
+++ b/packages/nextjs/src/pages/registration.ts
@@ -1,110 +1,20 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
-import { useEffect, useState } from "react"
-import { useRouter } from "next/router"
-import { useSearchParams } from "next/navigation"
-import {
- FlowType,
- handleFlowError,
- OnRedirectHandler,
- RegistrationFlow,
- ApiResponse,
-} from "@ory/client-fetch"
-
import { clientSideFrontendClient } from "./client"
-import { rewriteJsonResponse } from "../utils/rewrite"
-import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
-
-export function toValue(res: ApiResponse): Promise {
- // Remove all undefined values from the response (array and object) using lodash:
- // Remove all (nested) undefined values from the response using lodash
- return res.value().then((v) => rewriteJsonResponse(v))
-}
-
-export function onValidationError(value: T): T {
- return value
-}
-
-const toBrowserEndpointRedirect = (
- params: URLSearchParams,
- flowType: FlowType,
-) =>
- guessPotentiallyProxiedOrySdkUrl({
- knownProxiedUrl: window.location.origin,
- }) +
- "/self-service/" +
- flowType.toString() +
- "/browser?" +
- new URLSearchParams(params).toString()
-
-const handleRestartFlow =
- (searchParams: URLSearchParams, flowType: FlowType) => () => {
- window.location.assign(toBrowserEndpointRedirect(searchParams, flowType))
- }
-
-function useOnRedirect(): OnRedirectHandler {
- const router = useRouter()
- return (url: string, external: boolean) => {
- if (external) {
- window.location.assign(url)
- } else {
- router.push(url)
- }
- }
-}
-
-export function useRegistrationFlow(): RegistrationFlow | null | void {
- const [flow, setFlow] = useState()
- const router = useRouter()
- const searchParams = useSearchParams()
- const onRestartFlow = handleRestartFlow(searchParams, FlowType.Registration)
- const onRedirect = useOnRedirect()
-
- const errorHandler = handleFlowError({
- onValidationError,
- onRestartFlow,
- onRedirect,
- })
-
- const handleSetFlow = (flow: RegistrationFlow) => {
- setFlow(flow)
-
- // Use the router to update the `flow` search parameter only
- return router.replace({
- query: { flow: flow.id },
+import { createUseFlowFactory } from "./flow"
+import { FlowType } from "@ory/client-fetch"
+
+export const useRegistrationFlow = createUseFlowFactory(
+ FlowType.Registration,
+ (params: URLSearchParams) => {
+ return clientSideFrontendClient().createBrowserRegistrationFlowRaw({
+ returnTo: params.get("return_to") ?? undefined,
+ loginChallenge: params.get("registration_challenge") ?? undefined,
+ afterVerificationReturnTo:
+ params.get("after_verification_return_to") ?? undefined,
+ organization: params.get("organization") ?? undefined,
})
- }
-
- useEffect(() => {
- const id = searchParams.get("flow")
-
- // If the router is not ready yet, or we already have a flow, do nothing.
- if (!router.isReady || flow !== undefined) {
- return
- }
-
- if (!id) {
- clientSideFrontendClient
- .createBrowserRegistrationFlowRaw({
- returnTo: searchParams.get("return_to") ?? undefined,
- loginChallenge: searchParams.get("login_challenge") ?? undefined,
- afterVerificationReturnTo:
- searchParams.get("after_verification_return_to") ?? undefined,
- organization: searchParams.get("organization") ?? undefined,
- })
- .then(toValue)
- .then(handleSetFlow)
- .catch(errorHandler)
- return
- }
-
- clientSideFrontendClient
- .getRegistrationFlowRaw({ id })
- .then(toValue)
- .then(handleSetFlow)
- .catch(errorHandler)
- }, [searchParams, router, router.isReady, flow])
-
- return flow
-}
+ },
+ (id) => clientSideFrontendClient().getRegistrationFlowRaw({ id }),
+)
diff --git a/packages/nextjs/src/pages/utils.ts b/packages/nextjs/src/pages/utils.ts
index b85af654c..5cbf7e8d9 100644
--- a/packages/nextjs/src/pages/utils.ts
+++ b/packages/nextjs/src/pages/utils.ts
@@ -1,2 +1,38 @@
// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
+
+import { FlowType, OnRedirectHandler } from "@ory/client-fetch"
+import { guessPotentiallyProxiedOrySdkUrl } from "../utils/sdk"
+import { useRouter } from "next/router"
+
+export function onValidationError(value: T): T {
+ return value
+}
+
+export const toBrowserEndpointRedirect = (
+ params: URLSearchParams,
+ flowType: FlowType,
+) =>
+ guessPotentiallyProxiedOrySdkUrl({
+ knownProxiedUrl: window.location.origin,
+ }) +
+ "/self-service/" +
+ flowType.toString() +
+ "/browser?" +
+ new URLSearchParams(params).toString()
+
+export const handleRestartFlow =
+ (searchParams: URLSearchParams, flowType: FlowType) => () => {
+ window.location.assign(toBrowserEndpointRedirect(searchParams, flowType))
+ }
+
+export function useOnRedirect(): OnRedirectHandler {
+ const router = useRouter()
+ return (url: string, external: boolean) => {
+ if (external) {
+ window.location.assign(url)
+ } else {
+ router.push(url)
+ }
+ }
+}
diff --git a/packages/nextjs/src/pages/verification.ts b/packages/nextjs/src/pages/verification.ts
new file mode 100644
index 000000000..5c1a513d8
--- /dev/null
+++ b/packages/nextjs/src/pages/verification.ts
@@ -0,0 +1,16 @@
+// Copyright © 2024 Ory Corp
+// SPDX-License-Identifier: Apache-2.0
+
+import { clientSideFrontendClient } from "./client"
+import { createUseFlowFactory } from "./flow"
+import { FlowType } from "@ory/client-fetch"
+
+export const useVerificationFlow = createUseFlowFactory(
+ FlowType.Verification,
+ (params: URLSearchParams) => {
+ return clientSideFrontendClient().createBrowserVerificationFlowRaw({
+ returnTo: params.get("return_to") ?? undefined,
+ })
+ },
+ (id) => clientSideFrontendClient().getVerificationFlowRaw({ id }),
+)
diff --git a/packages/nextjs/src/utils/utils.ts b/packages/nextjs/src/utils/utils.ts
index d0f63a02e..598f2cb54 100644
--- a/packages/nextjs/src/utils/utils.ts
+++ b/packages/nextjs/src/utils/utils.ts
@@ -6,6 +6,8 @@ import { serialize, SerializeOptions } from "cookie"
import { FlowParams, OryConfig, QueryParams } from "../types"
import { guessCookieDomain } from "./cookie"
import { defaultForwardedHeaders } from "./headers"
+import { ApiResponse } from "@ory/client-fetch"
+import { rewriteJsonResponse } from "./rewrite"
export function onValidationError(value: T): T {
return value
@@ -75,3 +77,9 @@ export function joinUrlPaths(baseUrl: string, relativeUrl: string): string {
return new URL(relative.toString(), baseUrl).href
}
+
+export function toValue(res: ApiResponse): Promise {
+ // Remove all undefined values from the response (array and object) using lodash:
+ // Remove all (nested) undefined values from the response using lodash
+ return res.value().then((v) => rewriteJsonResponse(v))
+}