Reputation: 8693
I like the pattern used on next-auth
→ https://next-auth.js.org/getting-started/client#custom-client-session-handling
Basically, the gist is to put .auth = true
& then check it in _app.tsx
like:
export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
<SessionProvider session={session}>
{Component.auth ? (
<Auth>
<Component {...pageProps} />
</Auth>
) : (
<Component {...pageProps} />
)}
</SessionProvider>
)
}
function Auth({ children }) {
const { data: session, status } = useSession()
const isUser = !!session?.user
React.useEffect(() => {
if (status === "loading") return // Do nothing while loading
if (!isUser) signIn() // If not authenticated, force log in
}, [isUser, status])
if (isUser) {
return children
}
// Session is being fetched, or no user.
// If no user, useEffect() will redirect.
return <div>Loading...</div>
}
Is there a way to do that in iron-session
?
Upvotes: 1
Views: 1519
Reputation: 8693
I've found a decent solution.
import { GetServerSidePropsContext, GetServerSidePropsResult, NextApiHandler } from 'next'
import { withIronSessionApiRoute, withIronSessionSsr } from 'iron-session/next'
import { IronSessionOptions } from 'iron-session'
export const IRON_OPTIONS: IronSessionOptions = {
cookieName: process.env.IRON_COOKIE_NAME,
password: process.env.IRON_PASSWORD,
// 1 minute ttl = 1 + 1, 60 minute ttl = 60 + 1
// ttl: 60 * (1 + 1),
}
function withSessionRoute(handler: NextApiHandler) {
return withIronSessionApiRoute(handler, IRON_OPTIONS)
}
// Theses types are compatible with InferGetStaticPropsType https://nextjs.org/docs/basic-features/data-fetching#typescript-use-getstaticprops
function withSessionSsr<P extends { [key: string]: unknown } = { [key: string]: unknown }>(
handler: (
context: GetServerSidePropsContext
) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>
) {
return withIronSessionSsr(handler, IRON_OPTIONS)
}
export { withSessionRoute, withSessionSsr }
withSessionRoute
is used for /api
routes & withSessionSsr
for components.
import { withSessionSsr } from '@/utils/index'
const ProtectedRoute = () => {
return <div>Protected Router</div>
}
export const getServerSideProps = withSessionSsr(async function ({ req, res }) {
const admin = req.session.admin
if (admin === undefined) {
res.setHeader('location', '/admin')
res.statusCode = 302
res.end()
return {
props: {
admin: { isLoggedIn: false } as Admin,
},
}
}
return {
props: { admin },
}
})
I redirect the protected page to /admin
if the admin
session is not found.
Upvotes: 1
Reputation: 9811
I was looking for the same solution with iron-session
, here is what I ended up with (_app.tsx
):
function MyApp({
Component,
pageProps
}: AppProps
) {
store.dispatch(update(pageProps.user));
return (
<div>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</div>
);
}
MyApp.getInitialProps = async function (appContext: AppContext) {
const req = appContext.ctx.req
const res = appContext.ctx.res;
const session = await getIronSession(req, res, sessionOptions);
const DEFAULT_PROPS = {
pageProps: {},
};
if (session.user) {
return {
...DEFAULT_PROPS,
pageProps: {
user: session.user,
},
};
}
return DEFAULT_PROPS;
}
Notice store.dispatch
which fills up the store with user data.
Upvotes: 1