-
Hey, Following some of the great implementation in creating a HOC for My issue however is that for some reason I noticed a huge increase in TTFB on a simple login page. This appears to come from here is the HOC import { GetServerSidePropsContext } from 'next'
import { Session } from 'next-auth'
import { getCsrfToken, getSession } from 'next-auth/react'
// Reference: https://github.com/vercel/next.js/discussions/10925#discussioncomment-147287
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AsyncReturnType<T extends (...args: any) => any> = T extends (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...args: any
) => Promise<infer U>
? U
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends (...args: any) => infer U
? U
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
any
export type InferWithAuthServerSideProps<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends (...args: any) => Promise<{ props: any }>,
> = AsyncReturnType<T>['props']
type WithAuthServerSidePropsOptions = {
authenticatedPage?: boolean
destination?: string
}
export type AuthenticatedPageProps = {
session: Session
}
type EmptyProps = {
props: Record<string, unknown>
}
type DefaultWithAuthServerSideProps = {
session: Session | null
}
export const withAuthServerSideProps = <T extends EmptyProps = EmptyProps>(
getServerSidePropsFunc?: (
ctx: GetServerSidePropsContext,
session: Session | null | undefined,
) => Promise<T>,
options: WithAuthServerSidePropsOptions = {},
) => {
return async function getMergedServerSideProps(
ctx: GetServerSidePropsContext,
): Promise<{ props: T['props'] & DefaultWithAuthServerSideProps }> {
let userSession: Session | null
try {
userSession = await getSession(ctx)
} catch {
userSession = null
}
if (options.authenticatedPage && !userSession) {
return {
redirect: {
destination: options.destination,
permanent: false,
},
// We have to trick the TS compiler here.
} as unknown as { props: T['props'] & DefaultWithAuthServerSideProps }
}
if (getServerSidePropsFunc) {
const serverSidePropsResult = (await getServerSidePropsFunc(ctx, userSession)) as any
if ('redirect' in serverSidePropsResult) {
return {
redirect: { ...serverSidePropsResult.redirect },
} as unknown as { props: T['props'] & DefaultWithAuthServerSideProps }
}
return {
props: {
csrfToken: await getCsrfToken(ctx),
session: userSession,
...(serverSidePropsResult.props || {}),
},
}
}
return {
props: {
session: userSession,
},
}
}
} My config file: import Credentials from 'next-auth/providers/credentials'
import { nextAuthLogin } from '@modules/auth/components/login'
import jwt from 'jsonwebtoken'
import { NextAuthOptions } from 'next-auth/index.d'
import { nextAuthMfaConfirm } from '@modules/auth/components/mfa'
const NextAuthConfig = (): NextAuthOptions => {
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
return {
// https://next-auth.js.org/configuration/providers
// Setup multiple providers for multi step auth
// https://next-auth.js.org/providers/credentials#multiple-providers
providers: [
Credentials({
id: 'login',
// The name to display on the sign in form (e.g. 'Sign in with...')
name: 'Login',
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
credentials: {},
authorize: nextAuthLogin,
}),
Credentials({
id: 'mfa',
name: 'Mfa',
credentials: {},
authorize: nextAuthMfaConfirm,
}),
],
// Database optional. MySQL, Maria DB, Postgres and MongoDB are supported.
// https://next-auth.js.org/configuration/databases
//
// Notes:
// * You must to install an appropriate node_module for your database
// * The Email provider requires a database (OAuth providers do not)
// database: process.env.DATABASE_URL,
// The secret should be set to a reasonably long random string.
// It is used to sign cookies and to sign and encrypt JSON Web Tokens, unless
// a separate secret is defined explicitly for encrypting the JWT.
secret: process.env.SECRET,
session: {
// Use JSON Web Tokens for session instead of database sessions.
// This option can be used with or without a database for users/accounts.
// Note: `jwt` is automatically set to `true` if no database is specified.
jwt: true,
// Seconds - How long until an idle session expires and is no longer valid.
// maxAge: 30 * 24 * 60 * 60, // 30 days
// Seconds - Throttle how frequently to write to database to extend a session.
// Use it to limit write operations. Set to 0 to always update the database.
// Note: This option is ignored if using JSON Web Tokens
// updateAge: 24 * 60 * 60, // 24 hours
},
// JSON Web tokens are only used for sessions if the `jwt: true` session
// option is set - or by default if no database is specified.
// https://next-auth.js.org/configuration/options#jwt
jwt: {
// A secret to use for key generation (you should set this explicitly)
// secret: process.env.SECRET,
// Set to true to use encryption (default: false)
// encryption: true,
// You can define your own encode/decode functions for signing and encryption
// if you want to override the default behaviour.
// encode: async ({ secret, token, maxAge }) => {
// const jwtClaims = {
// sub: token.sub.toString(),
// name: token.name,
// email: token.email,
// iat: Date.now() / 1000,
// exp: Math.floor(Date.now() / 1000) + 24 * 60 * 60,
// 'https://hasura.io/jwt/claims': {
// 'x-hasura-allowed-roles': ['user'],
// 'x-hasura-default-role': 'user',
// 'x-hasura-role': 'user',
// 'x-hasura-user-id': token.id,
// },
// }
// const encodedToken = jwt.sign(jwtClaims, secret, { algorithm: 'HS256' })
// return encodedToken
// },
// decode: async ({ secret, token, maxAge }) => {
// const decodedToken = jwt.verify(token, secret, { algorithms: ['HS256'] })
// return decodedToken
// },
},
// You can define custom pages to override the built-in pages.
// The routes shown here are the default URLs that will be used when a custom
// pages is not specified for that route.
// https://next-auth.js.org/configuration/pages
pages: {
signIn: '/auth/login', // Displays signin buttons
},
// Callbacks are asynchronous functions you can use to control what happens
// when an action is performed.
// https://next-auth.js.org/configuration/callbacks
callbacks: {
// async signIn({ user, account, profile }) {
// return Promise.resolve(true)
// },
// async redirect(url, baseUrl) { return baseUrl },
session: async ({ session, user, token }) => {
return Promise.resolve(token)
},
jwt: async ({ token, user }): Promise<any> => {
if (user) {
console.log('user data exists', {
user,
...token,
})
const { accessToken, refreshToken, ...rest } = user
return Promise.resolve({
user: { ...rest },
...token,
accessToken,
refreshToken,
})
}
// and or session client access
return Promise.resolve(token)
},
},
// Events are useful for logging
// https://next-auth.js.org/configuration/events
events: {},
// Enable debug messages in the console if you are having problems
debug: true,
}
}
export { NextAuthConfig } |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 10 replies
-
Probably related #1535 I'm going to work on this when v4 lands in stable. That said, getServerSideProps gives you automatically a higher TTFB, since it will perform a blocking server-side render on every request, and I would try to avoid if possible, depending on your usecase. You might also drop any unnecessary 10-15 seconds sounds a bit harsh in any case though. I cannot believe that difference would come from next-auth. 👀 Is this happening locally or on your deployed page? Where do you host in that case? |
Beta Was this translation helpful? Give feedback.
-
Marking this as answer this as I believe once I do the production build the results should be faster. Thanks @balazsorban44 |
Beta Was this translation helpful? Give feedback.
Marking this as answer this as I believe once I do the production build the results should be faster. Thanks @balazsorban44