From c4912bbb945500b3ee8b62b89a6c456d3e623af2 Mon Sep 17 00:00:00 2001 From: Simon Emanuelsson Date: Wed, 24 Apr 2024 12:37:47 +0200 Subject: [PATCH 1/2] feat(WEB-215): add refresh_token --- app/[lang]/(live)/(protected)/error.tsx | 22 ++++++++ app/[lang]/(live)/layout.tsx | 2 +- auth.ts | 48 ++++++++++++++++-- lib/trpc/Provider.tsx | 67 +++++++++++++++++++++++-- middlewares/authRequired.ts | 5 ++ server/errors/trpc.ts | 10 ++++ server/trpc.ts | 4 ++ types/auth.d.ts | 27 +++++----- types/authError.ts | 3 ++ types/jwt.d.ts | 8 ++- 10 files changed, 175 insertions(+), 21 deletions(-) create mode 100644 app/[lang]/(live)/(protected)/error.tsx create mode 100644 types/authError.ts diff --git a/app/[lang]/(live)/(protected)/error.tsx b/app/[lang]/(live)/(protected)/error.tsx new file mode 100644 index 000000000..ed96c6ec6 --- /dev/null +++ b/app/[lang]/(live)/(protected)/error.tsx @@ -0,0 +1,22 @@ +"use client" +import { useParams } from "next/navigation" +import { useEffect } from "react" + +import { login } from "@/constants/routes/handleAuth" +import { SESSION_EXPIRED } from "@/server/errors/trpc" + +import type { ErrorPage } from "@/types/next/error" +import type { LangParams } from "@/types/params" + +export default function ProtectedError({ error }: ErrorPage) { + const params = useParams() + + useEffect(() => { + if (error.message === SESSION_EXPIRED) { + const loginUrl = login[params.lang] + window.location.assign(loginUrl) + } + }, [error.message, params.lang]) + + return null +} diff --git a/app/[lang]/(live)/layout.tsx b/app/[lang]/(live)/layout.tsx index 921f5a8a0..34e4cf3b5 100644 --- a/app/[lang]/(live)/layout.tsx +++ b/app/[lang]/(live)/layout.tsx @@ -43,7 +43,7 @@ export default async function RootLayout({ - {children} + {children} diff --git a/auth.ts b/auth.ts index 3436d544b..59e85c82d 100644 --- a/auth.ts +++ b/auth.ts @@ -55,7 +55,8 @@ export const config = { async signIn() { return true }, - async session({ session, token, user }) { + async session({ session, token }) { + session.error = token.error if (session.user) { return { ...session, @@ -95,13 +96,54 @@ export const config = { async authorized({ auth, request }) { return true }, - async jwt({ session, token, trigger, account }) { + async jwt({ account, session, token, trigger }) { if (account) { return { access_token: account.access_token, + expires_at: account.expires_at + ? account.expires_at * 1000 + : undefined, + refresh_token: account.refresh_token, + } + } else if (Date.now() < token.expires_at) { + return token + } else { + try { + const response = await fetch( + `${env.CURITY_ISSUER_USER}/oauth/v2/token`, + { + body: new URLSearchParams({ + client_id: env.CURITY_CLIENT_ID_USER, + client_secret: env.CURITY_CLIENT_SECRET_USER, + grant_type: "refresh_token", + refresh_token: token.refresh_token, + }), + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + method: "POST", + } + ) + + const tokens = await response.json() + + if (!response.ok) { + throw tokens + } + + return { + ...token, + access_token: tokens.access_token, + expires_at: tokens.expires_at, + refresh_token: tokens.refresh_token ?? token.refresh_token, + } + } catch (error) { + return { + ...token, + error: "RefreshAccessTokenError" as const, + } } } - return token }, }, // events: { diff --git a/lib/trpc/Provider.tsx b/lib/trpc/Provider.tsx index 4f755ae48..78576e492 100644 --- a/lib/trpc/Provider.tsx +++ b/lib/trpc/Provider.tsx @@ -1,14 +1,23 @@ "use client" -import { QueryClient, QueryClientProvider } from "@tanstack/react-query" -import { httpBatchLink, loggerLink } from "@trpc/client" +import { + QueryCache, + QueryClient, + QueryClientProvider, +} from "@tanstack/react-query" +import { httpBatchLink, loggerLink,TRPCClientError } from "@trpc/client" +import { AnyTRPCRouter } from "@trpc/server" import { useState } from "react" +import { login } from "@/constants/routes/handleAuth" import { env } from "@/env/client" +import { SessionExpiredError } from "@/server/errors/trpc" import { transformer } from "@/server/transformer" import { trpc } from "./client" +import { LangParams } from "@/types/params" + function initializeTrpcClient() { // Locally we set nextjs to run on port to 3000 so that we always guarantee // that trpc and next are running on the same port. @@ -32,8 +41,58 @@ function initializeTrpcClient() { }) } -export default function TrpcProvider({ children }: React.PropsWithChildren) { - const [queryClient] = useState(() => new QueryClient({})) +export default function TrpcProvider({ + children, + lang, +}: React.PropsWithChildren) { + const [queryClient] = useState( + () => + new QueryClient({ + queryCache: new QueryCache({ + async onError(error) { + if (error instanceof TRPCClientError) { + const appError: TRPCClientError = error + console.log({ appError }) + if (appError.data?.code === "UNAUTHORIZED") { + if (appError.data?.cause instanceof SessionExpiredError) { + const loginUrl = login[lang] + window.location.assign(loginUrl) + } + } + } + }, + }), + defaultOptions: { + queries: { + staleTime: 3000, + retry(failureCount, error) { + if (error instanceof TRPCClientError) { + const appError: TRPCClientError = error + + // Do not retry query requests that got UNAUTHORIZED error. + // It won't make a difference sending the same request again. + + if (appError.data?.code) { + if ( + [ + "UNAUTHORIZED", + "INTERNAL_SERVER_ERROR", + "FORBIDDEN", + ].includes(appError.data.code) + ) { + return false + } + } + } + + // Retry all client requests that fail (and are not handled above) + // at most 3 times. + return failureCount < 3 + }, + }, + }, + }) + ) const [trpcClient] = useState(() => initializeTrpcClient()) return ( diff --git a/middlewares/authRequired.ts b/middlewares/authRequired.ts index 3eecd0289..1332d4bc8 100644 --- a/middlewares/authRequired.ts +++ b/middlewares/authRequired.ts @@ -42,6 +42,11 @@ export const middleware = auth(async (request) => { const lang = findLang(nextUrl.pathname)! const isLoggedIn = !!request.auth + const hasError = request.auth?.error + + if (hasError) { + throw internalServerError(request.auth?.error) + } if (isLoggedIn) { const headers = new Headers(request.headers) diff --git a/server/errors/trpc.ts b/server/errors/trpc.ts index 12ef04df9..0acf19819 100644 --- a/server/errors/trpc.ts +++ b/server/errors/trpc.ts @@ -39,3 +39,13 @@ export function internalServerError(cause?: unknown) { cause, }) } + +export const SESSION_EXPIRED = "SESSION_EXPIRED" +export class SessionExpiredError extends Error {} +export function sessionExpiredError() { + return new TRPCError({ + code: "UNAUTHORIZED", + message: SESSION_EXPIRED, + cause: new SessionExpiredError(SESSION_EXPIRED), + }) +} diff --git a/server/trpc.ts b/server/trpc.ts index 54a4d7f68..66312f01e 100644 --- a/server/trpc.ts +++ b/server/trpc.ts @@ -34,6 +34,10 @@ export const protectedProcedure = t.procedure.use(async function (opts) { console.info(`path: ${opts.path} | type: ${opts.type}`) } + if (session?.error === "RefreshAccessTokenError") { + throw unauthorizedError() + } + if (!session?.user) { throw unauthorizedError() } diff --git a/types/auth.d.ts b/types/auth.d.ts index 1b06c1234..3cf582207 100644 --- a/types/auth.d.ts +++ b/types/auth.d.ts @@ -1,8 +1,23 @@ import type { JWT } from "next-auth/jwt" +import type { RefreshTokenError } from "./authError" + // Module augmentation // https://authjs.dev/getting-started/typescript#popular-interfaces-to-augment declare module "next-auth" { + /** + * The shape of the account object returned in the OAuth providers' `account` callback, + * Usually contains information about the provider being used, like OAuth tokens (`access_token`, etc). + */ + interface Account {} + + /** + * Returned by `useSession`, `auth`, contains information about the active session. + */ + interface Session extends RefreshTokenError { + token: JWT + } + /** * The shape of the user object returned in the OAuth providers' `profile` callback, * or the second parameter of the `session` callback, when using a database. @@ -11,16 +26,4 @@ declare module "next-auth" { given_name: string sub: string } - /** - * The shape of the account object returned in the OAuth providers' `account` callback, - * Usually contains information about the provider being used, like OAuth tokens (`access_token`, etc). - */ - interface Account { } - - /** - * Returned by `useSession`, `auth`, contains information about the active session. - */ - interface Session { - token: JWT - } } diff --git a/types/authError.ts b/types/authError.ts new file mode 100644 index 000000000..2c2217908 --- /dev/null +++ b/types/authError.ts @@ -0,0 +1,3 @@ +export interface RefreshTokenError { + error?: "RefreshAccessTokenError" +} diff --git a/types/jwt.d.ts b/types/jwt.d.ts index 97fa95704..b1dbc1af8 100644 --- a/types/jwt.d.ts +++ b/types/jwt.d.ts @@ -1,8 +1,14 @@ +import type { DefaultJWT } from "next-auth/jwt" + +import type { RefreshTokenError } from "./authError" + // Module augmentation // https://authjs.dev/getting-started/typescript#popular-interfaces-to-augment declare module "next-auth/jwt" { /** Returned by the `jwt` callback and `auth`, when using JWT sessions */ - interface JWT { + interface JWT extends DefaultJWT, RefreshTokenError { access_token: string + expires_at: number + refresh_token: string } } From 476e9f75821cd882c49c4c69913b7b01a75bd2c2 Mon Sep 17 00:00:00 2001 From: Michael Zetterberg Date: Mon, 20 May 2024 09:05:49 +0200 Subject: [PATCH 2/2] fix(auth): make things work --- app/[lang]/(live)/(protected)/error.tsx | 22 -------- app/[lang]/(live)/error.tsx | 15 +++++- .../Blocks/Overview/Buttons/CopyButton.tsx | 2 +- .../MyPages/Blocks/Overview/Friend/index.tsx | 2 +- .../Overview/Stats/TotalPoints/index.tsx | 4 +- lib/api/endpoints.ts | 1 + lib/graphql/Query/ResolveEntry.graphql | 8 +++ lib/trpc/Provider.tsx | 2 +- lib/trpc/server.ts | 4 +- middleware.ts | 9 +++- middlewares/authRequired.ts | 6 +-- middlewares/cmsContent.ts | 4 +- middlewares/myPages.ts | 52 +++++++++++++++---- server/errors/next.ts | 41 ++++++++------- server/routers/user/output.ts | 14 ++--- server/routers/user/query.ts | 5 +- server/trpc.ts | 8 ++- types/requests/entry.ts | 1 + utils/entry.ts | 4 +- 19 files changed, 122 insertions(+), 82 deletions(-) delete mode 100644 app/[lang]/(live)/(protected)/error.tsx diff --git a/app/[lang]/(live)/(protected)/error.tsx b/app/[lang]/(live)/(protected)/error.tsx deleted file mode 100644 index ed96c6ec6..000000000 --- a/app/[lang]/(live)/(protected)/error.tsx +++ /dev/null @@ -1,22 +0,0 @@ -"use client" -import { useParams } from "next/navigation" -import { useEffect } from "react" - -import { login } from "@/constants/routes/handleAuth" -import { SESSION_EXPIRED } from "@/server/errors/trpc" - -import type { ErrorPage } from "@/types/next/error" -import type { LangParams } from "@/types/params" - -export default function ProtectedError({ error }: ErrorPage) { - const params = useParams() - - useEffect(() => { - if (error.message === SESSION_EXPIRED) { - const loginUrl = login[params.lang] - window.location.assign(loginUrl) - } - }, [error.message, params.lang]) - - return null -} diff --git a/app/[lang]/(live)/error.tsx b/app/[lang]/(live)/error.tsx index 738e4ff6f..0cdfc5a7d 100644 --- a/app/[lang]/(live)/error.tsx +++ b/app/[lang]/(live)/error.tsx @@ -1,23 +1,34 @@ "use client" // Error components must be Client Components -import { usePathname } from "next/navigation" +import { useParams, usePathname } from "next/navigation" import { useEffect } from "react" import { findLang } from "@/constants/languages" +import { login } from "@/constants/routes/handleAuth" +import { SESSION_EXPIRED } from "@/server/errors/trpc" import { firaMono, firaSans } from "@/app/[lang]/(live)/fonts" import styles from "./error.module.css" +import { LangParams } from "@/types/params" + export default function Error({ error, }: { error: Error & { digest?: string } }) { + const params = useParams() + useEffect(() => { // Log the error to an error reporting service console.error(error) - }, [error]) + + if (error.message === SESSION_EXPIRED) { + const loginUrl = login[params.lang] + window.location.assign(loginUrl) + } + }, [error, params.lang]) const pathname = usePathname() const lang = findLang(pathname) diff --git a/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx b/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx index db744f5a6..2d9ec3942 100644 --- a/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx +++ b/components/MyPages/Blocks/Overview/Buttons/CopyButton.tsx @@ -7,7 +7,7 @@ import type { User } from "@/types/user" export default function CopyButton({ membership }: Pick) { function handleCopy() { - console.log(`COPIED! (${membership.membershipNumber})`) + console.log(`COPIED! (${membership ? membership.membershipNumber : "N/A"})`) } return ( diff --git a/components/MyPages/Blocks/Overview/Friend/index.tsx b/components/MyPages/Blocks/Overview/Friend/index.tsx index 04c3e8773..ace0ea323 100644 --- a/components/MyPages/Blocks/Overview/Friend/index.tsx +++ b/components/MyPages/Blocks/Overview/Friend/index.tsx @@ -18,7 +18,7 @@ export default function Friend({ user }: FriendProps) {

{user.name}

- {user.membership.membershipNumber} + {user.membership ? user.membership.membershipNumber : "N/A"}

diff --git a/components/MyPages/Blocks/Overview/Stats/TotalPoints/index.tsx b/components/MyPages/Blocks/Overview/Stats/TotalPoints/index.tsx index 30b11088f..a1db42fb7 100644 --- a/components/MyPages/Blocks/Overview/Stats/TotalPoints/index.tsx +++ b/components/MyPages/Blocks/Overview/Stats/TotalPoints/index.tsx @@ -11,7 +11,9 @@ export default function TotalPoints({ user }: TotalPointsProps) {
Total Points -

{user.membership.currentPoints}

+

+ {user.membership ? user.membership.currentPoints : "N/A"} +

) } diff --git a/lib/api/endpoints.ts b/lib/api/endpoints.ts index d44a78891..2efc39cd8 100644 --- a/lib/api/endpoints.ts +++ b/lib/api/endpoints.ts @@ -6,6 +6,7 @@ export namespace endpoints { profile = "profile/v0/Profile", } export const enum v1 { + profile = "profile/v1/Profile", upcomingStays = "booking/v1/Stays/future", previousStays = "booking/v1/Stays/past", } diff --git a/lib/graphql/Query/ResolveEntry.graphql b/lib/graphql/Query/ResolveEntry.graphql index da848c0e9..016cee594 100644 --- a/lib/graphql/Query/ResolveEntry.graphql +++ b/lib/graphql/Query/ResolveEntry.graphql @@ -1,6 +1,14 @@ #import "../Fragments/Refs/System.graphql" query ResolveEntryByUrl($locale: String!, $url: String!) { + all_account_page(where: { url: $url }, locale: $locale) { + items { + system { + ...System + } + } + total + } all_content_page(where: { url: $url }, locale: $locale) { items { system { diff --git a/lib/trpc/Provider.tsx b/lib/trpc/Provider.tsx index 78576e492..fd9e09fd1 100644 --- a/lib/trpc/Provider.tsx +++ b/lib/trpc/Provider.tsx @@ -5,7 +5,7 @@ import { QueryClient, QueryClientProvider, } from "@tanstack/react-query" -import { httpBatchLink, loggerLink,TRPCClientError } from "@trpc/client" +import { httpBatchLink, loggerLink, TRPCClientError } from "@trpc/client" import { AnyTRPCRouter } from "@trpc/server" import { useState } from "react" diff --git a/lib/trpc/server.ts b/lib/trpc/server.ts index 662be7a2f..77b34c41d 100644 --- a/lib/trpc/server.ts +++ b/lib/trpc/server.ts @@ -23,7 +23,9 @@ export function serverClient() { if (error.code === "UNAUTHORIZED") { const lang = ctx?.lang || Lang.en const pathname = ctx?.pathname || "/" - redirect(`/${lang}/login?redirectTo=${encodeURIComponent(pathname)}`) + redirect( + `/${lang}/login?redirectTo=${encodeURIComponent(`/${lang}/${pathname}`)}` + ) } } diff --git a/middleware.ts b/middleware.ts index ec7ce426b..a838961e3 100644 --- a/middleware.ts +++ b/middleware.ts @@ -46,13 +46,20 @@ export const middleware: NextMiddleware = async (request, event) => { // We use x-lang as either Akamai or Netlify use x-language as the users preferred language result?.headers.set("x-lang", lang) - result?.headers.set("x-pathname", request.nextUrl.pathname) + result?.headers.set( + "x-pathname", + request.nextUrl.pathname.replace(`/${lang}`, "") + ) result?.headers.set("x-url", request.nextUrl.href) return result } } } catch (e) { if (e instanceof NextResponse && e.status) { + const cause = await e.json() + console.error(`Error in middleware`) + console.error(cause) + return NextResponse.rewrite( new URL(`/${lang}/middleware-error/${e.status}`, request.nextUrl), { diff --git a/middlewares/authRequired.ts b/middlewares/authRequired.ts index 1332d4bc8..268316d41 100644 --- a/middlewares/authRequired.ts +++ b/middlewares/authRequired.ts @@ -44,11 +44,7 @@ export const middleware = auth(async (request) => { const isLoggedIn = !!request.auth const hasError = request.auth?.error - if (hasError) { - throw internalServerError(request.auth?.error) - } - - if (isLoggedIn) { + if (isLoggedIn && !hasError) { const headers = new Headers(request.headers) headers.set("x-continue", "1") return NextResponse.next({ diff --git a/middlewares/cmsContent.ts b/middlewares/cmsContent.ts index cf72b02b7..c93c51246 100644 --- a/middlewares/cmsContent.ts +++ b/middlewares/cmsContent.ts @@ -19,7 +19,9 @@ export const middleware: NextMiddleware = async (request) => { const { contentType, uid } = await resolveEntry(pathNameWithoutLang, lang) if (!contentType || !uid) { - throw notFound() + throw notFound( + `Unable to resolve CMS entry for locale "${lang}": ${pathNameWithoutLang}` + ) } const isCurrent = contentType ? contentType.indexOf("current") >= 0 : false diff --git a/middlewares/myPages.ts b/middlewares/myPages.ts index 98382b3fb..a15ad07ba 100644 --- a/middlewares/myPages.ts +++ b/middlewares/myPages.ts @@ -2,23 +2,53 @@ import { NextResponse } from "next/server" import { findLang } from "@/constants/languages" import { myPages, overview } from "@/constants/routes/myPages" +import { env } from "@/env/server" +import { internalServerError, notFound } from "@/server/errors/next" + +import { resolve as resolveEntry } from "@/utils/entry" import type { NextMiddleware } from "next/server" import type { MiddlewareMatcher } from "@/types/middleware" -export const middleware: NextMiddleware = (request) => { - const lang = findLang(request.nextUrl.pathname)! - return NextResponse.redirect(overview[lang]) +export const middleware: NextMiddleware = async (request) => { + const { nextUrl } = request + const lang = findLang(nextUrl.pathname)! + + const myPagesRoot = myPages[lang] + if (nextUrl.pathname === myPagesRoot) { + if (!env.PUBLIC_URL) { + throw internalServerError("Missing value for env.PUBLIC_URL") + } + + const publicUrl = new URL(env.PUBLIC_URL) + const nextUrlClone = nextUrl.clone() + nextUrlClone.host = publicUrl.host + nextUrlClone.hostname = publicUrl.hostname + + const overviewUrl = overview[lang] + return NextResponse.redirect(new URL(overviewUrl, nextUrlClone)) + } + + const pathNameWithoutLang = nextUrl.pathname.replace(`/${lang}`, "") + const { uid } = await resolveEntry(pathNameWithoutLang, lang) + + if (!uid) { + throw notFound( + `Unable to resolve CMS entry for locale "${lang}": ${pathNameWithoutLang}` + ) + } + + const headers = new Headers(request.headers) + headers.set("x-uid", uid) + return NextResponse.next({ + request: { + headers, + }, + }) } export const matcher: MiddlewareMatcher = (request) => { - return [ - myPages.da, - myPages.de, - myPages.en, - myPages.fi, - myPages.no, - myPages.sv, - ].includes(request.nextUrl.pathname) + const lang = findLang(request.nextUrl.pathname)! + return request.nextUrl.pathname.startsWith(myPages[lang]) } diff --git a/server/errors/next.ts b/server/errors/next.ts index 2708bcc32..d38784020 100644 --- a/server/errors/next.ts +++ b/server/errors/next.ts @@ -1,42 +1,43 @@ import { NextResponse } from "next/server" -export function badRequest(body: unknown | string = "Bad request") { +export function badRequest(cause?: unknown) { const resInit = { status: 400, statusText: "Bad request", } - if (typeof body === "string") { - return new NextResponse(body, resInit) - } - - return NextResponse.json(body, resInit) + return NextResponse.json( + { + cause, + }, + resInit + ) } -export function notFound(body: unknown | string = "Not found") { +export function notFound(cause?: unknown) { const resInit = { status: 404, statusText: "Not found", } - if (typeof body === "string") { - return new NextResponse(body, resInit) - } - - return NextResponse.json(body, resInit) + return NextResponse.json( + { + cause, + }, + resInit + ) } -export function internalServerError( - body: unknown | string = "Internal Server Error" -) { +export function internalServerError(cause?: unknown) { const resInit = { status: 500, statusText: "Internal Server Error", } - if (typeof body === "string") { - return new NextResponse(body, resInit) - } - - return NextResponse.json(body, resInit) + return NextResponse.json( + { + cause, + }, + resInit + ) } diff --git a/server/routers/user/output.ts b/server/routers/user/output.ts index 14197afb4..85e5e91da 100644 --- a/server/routers/user/output.ts +++ b/server/routers/user/output.ts @@ -14,12 +14,14 @@ export const getUserSchema = z.object({ name: z.string(), language: z.string(), lastName: z.string(), - membership: z.object({ - currentPoints: z.number(), - expirationDate: z.string(), - membershipNumber: z.string(), - memberSince: z.string(), - }), + membership: z + .object({ + currentPoints: z.number(), + expirationDate: z.string(), + membershipNumber: z.string(), + memberSince: z.string(), + }) + .optional(), phoneNumber: z.string(), profileId: z.string(), }) diff --git a/server/routers/user/query.ts b/server/routers/user/query.ts index cc291748f..659df59c2 100644 --- a/server/routers/user/query.ts +++ b/server/routers/user/query.ts @@ -23,6 +23,7 @@ function fakingRequest(payload: T): Promise { export const userQueryRouter = router({ get: protectedProcedure.query(async function ({ ctx }) { const apiResponse = await api.get(api.endpoints.v0.profile, { + cache: "no-store", headers: { Authorization: `Bearer ${ctx.session.token.access_token}`, }, @@ -164,10 +165,6 @@ export const userQueryRouter = router({ } const apiJson = await apiResponse.json() - if (!apiJson.data?.length) { - throw notFound(apiJson) - } - const verifiedData = getStaysSchema.safeParse(apiJson) if (!verifiedData.success) { throw internalServerError(verifiedData.error) diff --git a/server/trpc.ts b/server/trpc.ts index 66312f01e..e09d79215 100644 --- a/server/trpc.ts +++ b/server/trpc.ts @@ -2,7 +2,11 @@ import { initTRPC } from "@trpc/server" import { env } from "@/env/server" -import { badRequestError, unauthorizedError } from "./errors/trpc" +import { + badRequestError, + sessionExpiredError, + unauthorizedError, +} from "./errors/trpc" import { transformer } from "./transformer" import type { Meta } from "@/types/trpc/meta" @@ -35,7 +39,7 @@ export const protectedProcedure = t.procedure.use(async function (opts) { } if (session?.error === "RefreshAccessTokenError") { - throw unauthorizedError() + throw sessionExpiredError() } if (!session?.user) { diff --git a/types/requests/entry.ts b/types/requests/entry.ts index 68ebf3bcf..a104d2134 100644 --- a/types/requests/entry.ts +++ b/types/requests/entry.ts @@ -13,6 +13,7 @@ const entryResolveSchema = z.object({ }) export const validateEntryResolveSchema = z.object({ + all_account_page: entryResolveSchema, all_content_page: entryResolveSchema, all_loyalty_page: entryResolveSchema, all_current_blocks_page: entryResolveSchema, diff --git a/utils/entry.ts b/utils/entry.ts index 06ca4875f..bd308cc08 100644 --- a/utils/entry.ts +++ b/utils/entry.ts @@ -28,9 +28,7 @@ export async function resolve(url: string, lang = Lang.en) { const validatedData = validateEntryResolveSchema.safeParse(data) if (!validatedData.success) { - console.error("Bad validation for `validateContentTypeDataSchema`") - console.error(validatedData.error) - throw internalServerError() + throw internalServerError(validatedData.error) } for (const value of Object.values(validatedData.data)) {