auth-helpers
auth-helpers copied to clipboard
Usage example with Next.js edge functions
Improve documentation
Describe the problem
There is no documentation on the use of auth helpers in Next.js edge functions to be used on Vercel or Cloudflare. The Edge Functions API is somewhat different, so it seems that createServerSupabaseClient from @supabase/auth-helpers-nextjs cannot be used directly. I found an example using a third-party library. But it would be great if we could perform Supabase authentication in edge functions using the official library from Supabase.
@ilyabo you should be able to use the createMiddlewareSupabaseClient: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#auth-with-nextjs-middleware
As middleware is always run on the edge: https://nextjs.org/docs/api-reference/edge-runtime
Which brings up a good point that we should likely rename createMiddlewareSupabaseClient to createEdgeSupabaseClient.
Thanks for flagging this!
@ilyabo you should be able to use the
createMiddlewareSupabaseClient: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#auth-with-nextjs-middlewareAs middleware is always run on the edge: https://nextjs.org/docs/api-reference/edge-runtime
Which brings up a good point that we should likely rename
createMiddlewareSupabaseClienttocreateEdgeSupabaseClient.Thanks for flagging this!
Do I need to pass Authorization header with fetch API to use nextjs edge functions?
I found out that, calling nextjs edge function from server component with fetch API, middleware doesn't receives req.cookies.
Without cookies I can't create supabase client because it will always return session null.
Server component code in app directory:
const getUser = async () => {
const res = await fetch('http://localhost:3000/api/user');
if (!res?.ok) { return null; }
return await res.json();
}
const Header = async () => {
const user = await getUser();
return(
<div>
{JSON.stringify(user)}
</div>
)
}
export default Header
This solution did not work for me. I am still receiving the same error
Code: EDGE_FUNCTION_INVOCATION_FAILED```
Is it possible to send a JSON via an edge API with createMiddlewareSupabaseClient?
In the code below, res is not setting a cookie unless being returned return res
Benefit would be sending session data upon login avoiding an additional getSession()
import { createMiddlewareSupabaseClient } from "@supabase/auth-helpers-nextjs";
import { NextRequest, NextResponse } from "next/server";
export const config = {
runtime: "edge",
};
export default async function handler(req: NextRequest) {
const res = NextResponse.next();
const { email, password } = (await req.json()) as {
email: string;
password: string;
};
const supabase = createMiddlewareSupabaseClient({ req, res });
const { data, error } = await supabase.auth.signInWithPassword({
email: email,
password: password,
});
if (data.session) {
// return res // correctly sets cookie but unable to attach a JSON
res; // not setting cookie but JSON returned
return new Response(
JSON.stringify({
session: data.session,
}),
{
status: 200,
statusText: "Successfully logged in",
headers: {
"content-type": "application/json",
},
}
);
}
}
@ilyabo you should be able to use the
createMiddlewareSupabaseClient: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#auth-with-nextjs-middlewareAs middleware is always run on the edge: https://nextjs.org/docs/api-reference/edge-runtime
Which brings up a good point that we should likely rename
createMiddlewareSupabaseClienttocreateEdgeSupabaseClient.Thanks for flagging this!
Ok, how do I get req and res in the server components? Those are required to call createMiddlewareSupabaseClient
Here's the workaround:
Suppose you have a route handler for a nodejs runtime like this:
// https://supabase.com/docs/guides/auth/auth-helpers/nextjs#route-handlers
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'
import type { Database } from '@/lib/database.types'
export async function POST(request: Request) {
const { title } = await request.json()
const supabase = createRouteHandlerClient<Database>({ cookies })
const { data } = await supabase.from('todos').insert({ title }).select()
return NextResponse.json(data)
}
You can change the runtime to edge by adding export const runtime = "edge" to the file. But this changes the APIs available for execution. Notably, cookies() from Vercel's next/headers no longer works. So you have to swap that out with the RequestCookies object from @edge-runtime/cookies (also from Vercel). The new one is not a callable function, its an object so you have to wrap it in a callback for the createFOOClient functions. The edge version would look like this:
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
+ import { RequestCookies } from "@edge-runtime/cookies";
- import { cookies } from 'next/headers'
import type { Database } from '@/lib/database.types'
export async function POST(request: Request) {
const { title } = await request.json()
+ const cookies = new RequestCookies(request.headers) as any;
+ const supabase = createRouteHandlerClient<Database>({ cookies: () => cookies })
- const supabase = createRouteHandlerClient<Database>({ cookies })
const { data } = await supabase.from('todos').insert({ title }).select()
return NextResponse.json(data)
}
Here's the workaround:
Suppose you have a route handler for a nodejs runtime like this:
// https://supabase.com/docs/guides/auth/auth-helpers/nextjs#route-handlers import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' import type { Database } from '@/lib/database.types' export async function POST(request: Request) { const { title } = await request.json() const supabase = createRouteHandlerClient<Database>({ cookies }) const { data } = await supabase.from('todos').insert({ title }).select() return NextResponse.json(data) }You can change the runtime to edge by adding
export const runtime = "edge"to the file. But this changes the APIs available for execution. Notably,cookies()from Vercel'snext/headersno longer works. So you have to swap that out with theRequestCookiesobject from @edge-runtime/cookies (also from Vercel). The new one is not a callable function, its an object so you have to wrap it in a callback for the createFOOClient functions. The edge version would look like this:import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' + import { RequestCookies } from "@edge-runtime/cookies"; - import { cookies } from 'next/headers' import type { Database } from '@/lib/database.types' export async function POST(request: Request) { const { title } = await request.json() + const cookies = new RequestCookies(request.headers) as any; + const supabase = createRouteHandlerClient<Database>({ cookies: () => cookies }) - const supabase = createRouteHandlerClient<Database>({ cookies }) const { data } = await supabase.from('todos').insert({ title }).select() return NextResponse.json(data) }
So far the cleanest approach. Thank you.
I am seeing this error
TypeError: requestHeaders.get is not a function at new RequestCookies (/node_modules/@edge-runtime/cookies/dist/index.js:102:35)
Any idea whats causing this?
Here's the workaround:
Suppose you have a route handler for a nodejs runtime like this:
// https://supabase.com/docs/guides/auth/auth-helpers/nextjs#route-handlers import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' import type { Database } from '@/lib/database.types' export async function POST(request: Request) { const { title } = await request.json() const supabase = createRouteHandlerClient<Database>({ cookies }) const { data } = await supabase.from('todos').insert({ title }).select() return NextResponse.json(data) }You can change the runtime to edge by adding
export const runtime = "edge"to the file. But this changes the APIs available for execution. Notably,cookies()from Vercel'snext/headersno longer works. So you have to swap that out with theRequestCookiesobject from @edge-runtime/cookies (also from Vercel). The new one is not a callable function, its an object so you have to wrap it in a callback for the createFOOClient functions. The edge version would look like this:import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' + import { RequestCookies } from "@edge-runtime/cookies"; - import { cookies } from 'next/headers' import type { Database } from '@/lib/database.types' export async function POST(request: Request) { const { title } = await request.json() + const cookies = new RequestCookies(request.headers) as any; + const supabase = createRouteHandlerClient<Database>({ cookies: () => cookies }) - const supabase = createRouteHandlerClient<Database>({ cookies }) const { data } = await supabase.from('todos').insert({ title }).select() return NextResponse.json(data) }
This should be added to the supabase documentation @kiwicopple
Not sure how I found this but thank goodness I did.
I think there is an issue with next/headers: https://github.com/vercel/next.js/issues/45371 . We're currently checking with the Vercel team.
But what about the OP – is it possible to run createServerSupabaseClient inside an edge function?
I don't see any way how the cookie from RequestCookies could be passed into it.
Context: I'm trying to use Supabase Auth inside a TRPC API callback.
I have verified that it works. You don’t pass the cookie in, you create a new object and pass on an anonymous function that returns that object (see above).
I’d be happy to share more details if the @supabase team would like or if people are still getting stuck here. On Aug 25, 2023 at 11:37 AM -0300, Alex Wilde @.***>, wrote:
But what about the OP – is it possible to run createServerSupabaseClient inside an edge function? I don't see any way how the cookie from RequestCookies could be passed into it. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>
I have verified that it works. You don’t pass the cookie in, you create a new object and pass on an anonymous function that returns that object (see above). I’d be happy to share more details if the @supabase team would like or if people are still getting stuck here. … On Aug 25, 2023 at 11:37 AM -0300, Alex Wilde @.>, wrote: But what about the OP – is it possible to run createServerSupabaseClient inside an edge function? I don't see any way how the cookie from RequestCookies could be passed into it. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.>
A complete example would help.
The Next.js team has stated that they have fixed this issue in their latest canary version. https://github.com/vercel/next.js/issues/45371#issuecomment-1719071552. I'm leaving this issue open until I get around to testing it out or someone having this issue report it has been fixed upstream. Do note that this isn't an auth-helpers issue, it's a Next.js issue.
The Next.js team has stated that they have fixed this issue in their latest canary version. vercel/next.js#45371 (comment). I'm leaving this issue open until I get around to testing it out or someone having this issue report it has been fixed upstream. Do note that this isn't an auth-helpers issue, it's a Next.js issue.
There's still a couple of issues open around using cookes in next13 for those who use edge runtime when deployed or windows when developing locally: https://github.com/vercel/next.js/issues/53331 https://github.com/vercel/next.js/issues/52176
The Next.js team has stated that they have fixed this issue in their latest canary version. vercel/next.js#45371 (comment). I'm leaving this issue open until I get around to testing it out or someone having this issue report it has been fixed upstream. Do note that this isn't an auth-helpers issue, it's a Next.js issue.
There's still a couple of issues open around using cookes in next13 for those who use edge runtime when deployed or windows when developing locally: vercel/next.js#53331 vercel/next.js#52176
@DevOfManyThings please read my comment carefully, this is not a auth-helpers issue. The issues you linked to are all old and none have tested the canary release which was mentioned in the issues I linked to only a few days ago. You should be testing this out with Next.js canary release and report back here if its not working.
@silentworks Hi, the problem with cookies still persists at [email protected]
@NastykSwED thanks for reporting this. I'm going to keep this issue open until there is a solution that truly fixes this issue. It might be useful to leave a reply on the Next.js issue to say it's still not working for you with a minimal reproducible example repo too. https://github.com/vercel/next.js/issues/45371#issuecomment-1719071552