66
loading...
This website collects cookies to deliver better user experience
/settings
page can only be used if the user is signed in./api/auth
to set a cookie based on whether a user signs in or out.onAuthStateChange
to detect a sign in or sign out and call this API route.enforceAuthenticated
to protect a route with one line of code.setAuthCookie
function defined in @supabase/gotrue-js
. This function takes a Next.js (or Express) request and response and sets or removes an auth cookie./api/auth
and simply call setAuthCookie
, passing it the request and response objects.// pages/api/auth.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { supabase } from './../../components/supabaseClient';
const handler = (req: NextApiRequest, res: NextApiResponse) => {
supabase.auth.api.setAuthCookie(req, res);
};
export default handler;
setAuthCookie
behaves like this:req
must be POST
request.session
and an event
.session
contains session data (as is provided by supabase.auth.session()
for example).event
is either SIGNED_IN
indicating a sign in or SIGNED_OUT
indicating a sign out./api/auth
endpoint to update the cookie accordingly.onAuthStateChange
function, which allows us to register a listener. This listener is called whenever a user signs in or out.App
component (usually _app.tsx
or _app.jsx
).useEffect(() => {
const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
updateSupabaseCookie(event, session);
});
return () => {
authListener?.unsubscribe();
};
});
async function updateSupabaseCookie(event: AuthChangeEvent, session: Session | null) {
await fetch('/api/auth', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json' }),
credentials: 'same-origin',
body: JSON.stringify({ event, session }),
});
}
event
indicating whether the user signed in or out and the current session
. This is exactly what the /api/auth
endpoint needs to update the auth cookie. Using fetch
, we send a simple POST
request to it to reflect this change.useUpdateAuthCookie
for example).getServerSideProps
.getServerSideProps
. If the user is signed in, we simply return; otherwise, we redirect the user to a sign in page. /signin
.export async function getServerSideProps({ req }) {
const { user } = await supabase.auth.api.getUserByCookie(req);
if (!user) {
return { props: {}, redirect: { destination: '/signin' } };
}
return { props: {} };
}
enforceAuthenticated
. This function takes an optional getServerSideProps
function and delegates to it in the case that the user is signed in.import { GetServerSideProps } from 'next';
import { supabase } from './supabaseClient';
const enforceAuthenticated: (inner?: GetServerSideProps) => GetServerSideProps = inner => {
return async context => {
const { req } = context;
const { user } = await supabase.auth.api.getUserByCookie(req);
if (!user) {
return { props: {}, redirect: { destination: '/signin' } };
}
if (inner) {
return inner(context);
}
return { props: {} };
};
};
export default enforceAuthenticated;
// pages/protected.tsx
import enforceAuthenticated from '../components/enforceAuthenticated';
export default function ProtectedPage() {
return <div>Protected Page</div>
}
export const getServerSideProps = enforceAuthenticated();
/protected
now, we are either redirected to /signin
when we are not signed in or the ProtectedPage
is rendered./api/auth
which updates an auth cookie based on a session and an event indicating a sign in or sign out.App
component to send every update to the authentication state to the /api/auth
endpoint, thereby updating the auth cookie.getUserByCookie
function to determine whether a user is signed in or out. Based on this, we either render the page or redirect the user to a sign in page.enforceAuthenticated
to reuse this functionality on as many routes as we want.setAuthCookie
/getUserByCookie
combination. Give it a read, it's an excellent post!