Skip to content

Commit

Permalink
fix: avoid redirect on always public paths (#5000)
Browse files Browse the repository at this point in the history
* type safe babel config

* avoid auth redirect for `_next`

* force render default error page on user miconfig

* add slash to _next path

* use `.some`

* add docs

* change from localhost

* add favicon to public path
  • Loading branch information
balazsorban44 committed Jul 23, 2022
1 parent 9f2cdad commit aedabc8
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 15 deletions.
4 changes: 4 additions & 0 deletions docs/docs/configuration/nextjs.md
Expand Up @@ -137,6 +137,10 @@ Callbacks are asynchronous functions you can use to control what happens when an

Specify URLs to be used if you want to create custom sign in, and error pages. Pages specified will override the corresponding built-in page.

:::note
This should match the `pages` configuration that's found in `[...nextauth].ts`.
:::

#### Example (default value)

```js
Expand Down
19 changes: 18 additions & 1 deletion docs/docs/errors.md
Expand Up @@ -152,7 +152,7 @@ This error occurs when there was an issue deleting the session from the database

---

### Other
### Configuration

#### MISSING_NEXTAUTH_API_ROUTE_ERROR

Expand All @@ -164,6 +164,23 @@ Make sure the file is there and the filename is written correctly.

In production, we expect you to define a `secret` property in your configuration. In development, this is shown as a warning for convenience. [Read more](/configuration/options#secret)


#### AUTH_ON_ERROR_PAGE_ERROR

You have a custom error page defined that was rendered due to an error, but the page also required authentication. To avoid an infinite redirect loop, NextAuth.js bailed out and rendered its default error page instead.

If you are using a Middleware, make sure you include the same `pages` configuration in your `middleware.ts` and `[...nextauth].ts` files. Or use the `matcher` option to only require authentication for certain sites (and exclude your custom error page).

If you do not use a Middleware, make sure you don't try redirecting the user to the sign-in page when hitting your custom error page.

Useful links:

- https://next-auth.js.org/configuration/nextjs#pages
- https://next-auth.js.org/configuration/pages
- https://nextjs.org/docs/advanced-features/middleware#matcher

### Other

#### oauth_callback_error expected 200 OK with body but no body was returned

This error might happen with some of the providers. It happens due to `openid-client`(which is peer dependency) node version mismatch. For instance, `openid-client` requires `>=14.2.0` for `lts/fermium` and has similar limits for the other versions. For the full list of the compatible node versions please see [package.json](https://github.com/panva/node-openid-client/blob/2a84e46992e1ebeaf685c3f87b65663d126e81aa/package.json#L78)
2 changes: 2 additions & 0 deletions packages/next-auth/config/babel.config.js
@@ -1,7 +1,9 @@
// @ts-check
// We aim to have the same support as Next.js
// https://nextjs.org/docs/getting-started#system-requirements
// https://nextjs.org/docs/basic-features/supported-browsers-features

/** @type {import("@babel/core").ConfigFunction} */
module.exports = (api) => {
const isTest = api.env("test")
if (isTest) {
Expand Down
25 changes: 20 additions & 5 deletions packages/next-auth/src/core/index.ts
Expand Up @@ -96,13 +96,28 @@ export async function NextAuthHandler<
// Bail out early if there's an error in the user config
const { pages, theme } = userOptions
logger.error(assertionResult.code, assertionResult)
if (pages?.error) {
return {
redirect: `${pages.error}?error=Configuration`,

const authOnErrorPage =
pages?.error &&
req.action === "signin" &&
req.query?.callbackUrl.startsWith(pages.error)

if (!pages?.error || authOnErrorPage) {
if (authOnErrorPage) {
logger.error(
"AUTH_ON_ERROR_PAGE_ERROR",
new Error(
`The error page ${pages?.error} should not require authentication`
)
)
}
const render = renderPage({ theme })
return render.error({ error: "configuration" })
}

return {
redirect: `${pages.error}?error=Configuration`,
}
const render = renderPage({ theme })
return render.error({ error: "configuration" })
}

const { action, providerId, error, method = "GET" } = req
Expand Down
20 changes: 11 additions & 9 deletions packages/next-auth/src/next/middleware.ts
Expand Up @@ -101,13 +101,18 @@ async function handleMiddleware(
options: NextAuthMiddlewareOptions | undefined,
onSuccess?: (token: JWT | null) => Promise<NextMiddlewareResult>
) {
const { pathname, search, origin } = req.nextUrl

const signInPage = options?.pages?.signIn ?? "/api/auth/signin"
const errorPage = options?.pages?.error ?? "/api/auth/error"
const basePath = parseUrl(process.env.NEXTAUTH_URL).path
// Avoid infinite redirect loop
const publicPaths = [signInPage, errorPage, "/_next", "/favicon.ico"]

// Avoid infinite redirects/invalid response
// on paths that never require authentication
if (
req.nextUrl.pathname.startsWith(basePath) ||
[signInPage, errorPage].includes(req.nextUrl.pathname)
pathname.startsWith(basePath) ||
publicPaths.some((p) => pathname.startsWith(p))
) {
return
}
Expand All @@ -119,7 +124,7 @@ async function handleMiddleware(
`\nhttps://next-auth.js.org/errors#no_secret`
)

const errorUrl = new URL(errorPage, req.nextUrl.origin)
const errorUrl = new URL(errorPage, origin)
errorUrl.searchParams.append("error", "Configuration")

return NextResponse.redirect(errorUrl)
Expand All @@ -139,11 +144,8 @@ async function handleMiddleware(
if (isAuthorized) return await onSuccess?.(token)

// the user is not logged in, redirect to the sign-in page
const signInUrl = new URL(signInPage, req.nextUrl.origin)
signInUrl.searchParams.append(
"callbackUrl",
`${req.nextUrl.pathname}${req.nextUrl.search}`
)
const signInUrl = new URL(signInPage, origin)
signInUrl.searchParams.append("callbackUrl", `${pathname}${search}`)
return NextResponse.redirect(signInUrl)
}

Expand Down

1 comment on commit aedabc8

@vercel
Copy link

@vercel vercel bot commented on aedabc8 Jul 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.