Comparison of the middleware implementation between Supabase Auth documentation and the nextjs-stripe-supabase.
In this article, we are going to compare the middleware implementation between Supabase Auth documentation and the nextjs-stripe-supabase.
- Supabase Auth Documentation
This is a good starting point for us to understand how the Supabase Auth middleware is configured so we can use that knowledge and draw some conclusions when we compare it with opensource projects such as nextjs-stripe-supabase
- Middleware in nextjs-subscription-payments.
But what’s the point of this? well, you will learn few techniques about how middleware for Supabase Auth can be configured.
Middleware in Supabase Auth Documentation
At step 4 — Hook up middleware in Supabase docs, you will find
code for middleware.ts
and utils/supabase/middleware.ts
.
middleware.ts
This below code is picked from Supabase documentation.
import { type NextRequest } from 'next/server'
import { updateSession } from '@/utils/supabase/middleware'
export async function middleware(request: NextRequest) {
return await updateSession(request)
}
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}
middleware.ts
has a function named middleware
and const named config
. These tiny details are important to keep in mind when comparing middleware in other projects in the later section of this article.
utils/supabase/middleware.ts
This below code is picked from Supabase documentation.
import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// The `setAll` method was called from a Server Component.
// This can be ignored if you have middleware refreshing
// user sessions.
}
},
},
}
)
}
Important steps performed here are:
-
Create a response object using NextResponse.
-
Then create a Supabase client using
CreateServerClient
, response from above step is toset
andget
cookies. -
Make a call to getUser(). This step is really important and make sure not to write any additional logic between
createServerClient
and thisgetUser
function. -
Redirect if the user is not logged in.
-
Return SupabaseResponse.
Also make sure to read the comments provided to help you understand the code better.
Middleware in Nextjs-Subscription-Payments
Based on the information from the above, found in Supabase Auth documentation, we need to review these below two files:
middleware.ts file
This below code is picked from nextjs-subscriptions-payments.
import { type NextRequest } from 'next/server';
import { updateSession } from '@/utils/supabase/middleware';
export async function middleware(request: NextRequest) {
return await updateSession(request);
}
export const config = {
matcher: [
/*
* Match all request paths except:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* - images - .svg, .png, .jpg, .jpeg, .gif, .webp
* Feel free to modify this pattern to include more paths.
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'
]
};
Comparing this with what is provided in Supabase auth documentation, there isn’t much difference.
utils/supabase/middleware.ts
This below code is picked from utils/supabase/middleware.ts.
import { createServerClient, type CookieOptions } from '@supabase/ssr';
import { type NextRequest, NextResponse } from 'next/server';
export const createClient = (request: NextRequest) => {
// Create an unmodified response
let response = NextResponse.next({
request: {
headers: request.headers
}
});
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return request.cookies.get(name)?.value;
},
set(name: string, value: string, options: CookieOptions) {
// If the cookie is updated, update the cookies for the request and response
request.cookies.set({
name,
value,
...options
});
response = NextResponse.next({
request: {
headers: request.headers
}
});
response.cookies.set({
name,
value,
...options
});
},
remove(name: string, options: CookieOptions) {
// If the cookie is removed, update the cookies for the request and response
request.cookies.set({
name,
value: '',
...options
});
response = NextResponse.next({
request: {
headers: request.headers
}
});
response.cookies.set({
name,
value: '',
...options
});
}
}
}
);
return { supabase, response };
};
export const updateSession = async (request: NextRequest) => {
try {
// This `try/catch` block is only here for the interactive tutorial.
// Feel free to remove once you have Supabase connected.
const { supabase, response } = createClient(request);
// This will refresh session if expired - required for Server Components
// https://supabase.com/docs/guides/auth/server-side/nextjs
await supabase.auth.getUser();
return response;
} catch (e) {
// If you are here, a Supabase client could not be created!
// This is likely because you have not set up environment variables.
// Check out http://localhost:3000 for Next Steps.
return NextResponse.next({
request: {
headers: request.headers
}
});
}
};
Comparing this with documentation, you will see the below differences:
-
updateSession
function is found in both, the documentation and this example above. -
There is a difference in the way client is created. In the Supabase Auth documentation, Supabase client is created with in the
updateSession
function itself, you do not see another function called. This is the
case inupdateSession
.createClient
function is called. -
createClient
looks very similar to the documentation. Except the cookies are handled differently. You will see functions such asset
andget
in this above example, whereas the Supabase auth documentation
uses methods such assetAll
andgetAll
. Both of these found to update the necessary cookies onrequest
andresponse
. -
The important step here is to call the
await supabase.auth.getUser()
and the comment just above this line in the above example —
“
// This will refresh session if expired — required for Server Components
// https://supabase.com/docs/guides/auth/server-side/nextjs
“
signifies that this line here is really important. -
There are redirects found to be happening in this example’s
updateSession
, but in the Supabase Auth documentation, you will see some redirects happening if the user does not exist. That’s not to say
nextjs-supscription-payments does not have redirects, it just happens in a different file. For example — signin/[id]/page.tsx
About us:
At Thinkthroo, we study large open source projects and provide architectural guides. We have developed reusable Components, built with tailwind, that you can use in your project.
We offer Next.js, React and Node development services.
Book a meeting with us to discuss your project.