optimistic-gold
optimistic-gold13mo ago

Supabase authentication not working

Hi, I have setup a refine (headless) + supabase project. I have enabled "Github" as an auth provider and have been following this page: https://refine.dev/docs/packages/documentation/data-providers/supabase/#this-premade-and-ready-to-use-login-screen-consist-loginpage-and-authprovider-concepts-behind-the-scenes I can login successfully (either with github or email/password) but a protected page still redirects me to "/login" route when I try to check for authentication on server side i.e. using getServerSideProps but it does let me in when using Authenticated component (see screenshot). How to make it work with getServerSideProps? Thanks,
Supabase | refine
Introduction
No description
16 Replies
kapa.ai
kapa.ai13mo ago
Hi @kunalvirk. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To achieve authentication control on the server-side with Next.js, you can use your authProvider's check function inside server side functions (getServerSideProps) to redirect unauthenticated users to other pages like login. First, you need to install the nookies package in your project. This package will be used to set/destroy cookies in the login, logout and check functions of your AuthProvider. You can install it using the following command:
npm i nookies
npm i nookies
Then, in your authProvider.ts file, you should implement the check function to check for authentication. This function will be used inside getServerSideProps to redirect unauthenticated users. Unfortunately, the extracts provided do not contain specific code examples for implementing the check function in authProvider.ts or using it inside getServerSideProps. For more detailed instructions and code examples, you can refer to the refine documentation on Next.js Authentication (https://refine.dev/docs/packages/documentation/routers/nextjs). Please note that for page level authentication, the server-side approach is recommended. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai13mo ago
<@798450536004452392> kapa.ai is still learning and improving, please let us how it did by reacting below
optimistic-gold
optimistic-gold13mo ago
@kapa.ai In the check method in authProvider: const { data, error } = await supabaseClient.auth.getSession(); this returns null on the server
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The getSession method from Supabase client is a client-side method and it won't work on the server-side because it relies on the window object to get the session from local storage, which is not available on the server-side. For server-side, you need to use cookies or similar methods to store and retrieve the session. You can use the nookies package to handle cookies on both server and client side in Next.js. Here's a general idea of how you can modify your check method to work on the server-side:
import { setCookie, destroyCookie, parseCookies } from 'nookies';

// ...

check: async (ctx) => {
const cookies = parseCookies(ctx);
const session = cookies['your-cookie-name'];

if (!session) {
return {
authenticated: false,
error: {
message: "Check failed",
name: "Session not found",
},
logout: true,
redirectTo: "/login",
};
}

return {
authenticated: true,
};
},
import { setCookie, destroyCookie, parseCookies } from 'nookies';

// ...

check: async (ctx) => {
const cookies = parseCookies(ctx);
const session = cookies['your-cookie-name'];

if (!session) {
return {
authenticated: false,
error: {
message: "Check failed",
name: "Session not found",
},
logout: true,
redirectTo: "/login",
};
}

return {
authenticated: true,
};
},
In the login method, you would set the cookie after successful login:
login: async ({ email, password }, ctx) => {
const { user, session, error } = await supabaseClient.auth.signIn({
email,
password,
});

if (error) {
return {
success: false,
error: error || new Error("Invalid email or password"),
};
}

if (session) {
setCookie(ctx, 'your-cookie-name', session, {
maxAge: 30 * 24 * 60 * 60,
path: '/',
});

return {
success: true,
redirectTo: "/",
};
}

return {
success: false,
error: error || new Error("Invalid email or password"),
};
},
login: async ({ email, password }, ctx) => {
const { user, session, error } = await supabaseClient.auth.signIn({
email,
password,
});

if (error) {
return {
success: false,
error: error || new Error("Invalid email or password"),
};
}

if (session) {
setCookie(ctx, 'your-cookie-name', session, {
maxAge: 30 * 24 * 60 * 60,
path: '/',
});

return {
success: true,
redirectTo: "/",
};
}

return {
success: false,
error: error || new Error("Invalid email or password"),
};
},
And in the logout method, you would destroy the cookie:
logout: async (ctx) => {
const { error } = await supabaseClient.auth.signOut();
if (error) {
return {
success: false,
error: error || new Error("Invalid email or password"),
};
}

destroyCookie(ctx, 'your-cookie-name', {
path: '/',
});

return {
success: true,
redirectTo: "/login",
};
},
logout: async (ctx) => {
const { error } = await supabaseClient.auth.signOut();
if (error) {
return {
success: false,
error: error || new Error("Invalid email or password"),
};
}

destroyCookie(ctx, 'your-cookie-name', {
path: '/',
});

return {
success: true,
redirectTo: "/login",
};
},
Please replace 'your-cookie-name' with the actual name you want to use for your cookie. Remember to pass the context (ctx) from getServerSideProps to the check, login, and logout methods. Please note that the code above is a general guide and might need adjustments based on your specific use case. For more detailed instructions and code examples, you can refer to the refine documentation on Next.js Authentication (https://refine.dev/docs/packages/documentation/routers/nextjs). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai13mo ago
<@798450536004452392> kapa.ai is still learning and improving, please let us how it did by reacting below
optimistic-gold
optimistic-gold13mo ago
@kapa.ai Supabase signInWithOAuth method does not return an access_token rather it sets two cookies named sb-access-token & sb-refresh-token. When checking the cookies using parseCookies method from nookies it return {} object
const cookies = parseCookies(ctx);
// returns {}
const cookies = parseCookies(ctx);
// returns {}
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The parseCookies method from nookies is used to parse the cookies from the request headers in the server-side context (ctx). If it's returning an empty object, it means that there are no cookies in the request headers. The signInWithOAuth method from Supabase sets the sb-access-token and sb-refresh-token cookies on the client-side. These cookies are httpOnly, which means they can't be accessed through JavaScript on the client-side for security reasons. They are automatically sent with every request to the server from the client's browser. If you're not seeing these cookies in your server-side context, it could be due to a few reasons: 1. The cookies are not being sent with the request. This could be because the request is not being made from the same domain that the cookies are set on. Cookies are only sent with requests that are made to the same domain. Make sure your server-side code is running on the same domain that your client-side code is running on. 2. The cookies are being blocked by the browser. Some browsers block third-party cookies by default. Make sure your browser settings allow third-party cookies. 3. The cookies are not being set correctly. Make sure the signInWithOAuth method is being called correctly and is successfully setting the cookies. If you're still having trouble, you might want to consider using a different method for server-side authentication. One common method is to use a JWT (JSON Web Token) that is stored in a secure httpOnly cookie. The JWT can be set by your server after successful authentication and then sent with every request to the server. Unfortunately, the provided extracts do not contain specific code examples or instructions for implementing this method with Supabase and refine. For more detailed instructions and code examples, you can refer to the Supabase documentation on server-side rendering (https://supabase.io/docs/guides/with-nextjs). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai13mo ago
<@798450536004452392> kapa.ai is still learning and improving, please let us how it did by reacting below
optimistic-gold
optimistic-gold13mo ago
@kapa.ai I confirm that the requests are being made from the same domain. Third party cookies also allowed. I can see the cookies being set as soon as the user is logged in successfuly
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- If you have confirmed that the cookies are being set correctly and the requests are being made from the same domain, then the cookies should be included in the request headers and should be accessible in the server-side context (ctx). However, if you're still not seeing the cookies using parseCookies(ctx), it could be due to the httpOnly attribute of the cookies. httpOnly cookies are not accessible through JavaScript and are only sent with HTTP requests. They are not accessible in the server-side context of Next.js because it's running in a Node.js environment, not a browser environment. To access the httpOnly cookies in your server-side code, you can use the req.headers.cookie property in the server-side context (ctx). This property contains a string with all the cookies that were sent with the request. Here's an example of how you can access the cookies:
const cookies = ctx.req.headers.cookie;
const cookies = ctx.req.headers.cookie;
This will give you a string with all the cookies. You can then parse this string to get the individual cookies:
const parsedCookies = cookie.parse(cookies);
const parsedCookies = cookie.parse(cookies);
Now parsedCookies should be an object with all the cookies that were sent with the request, including the httpOnly cookies. Please note that this method requires the cookie package. You can install it using the following command:
npm i cookie
npm i cookie
If you're still having trouble, it might be a good idea to check the ctx.req.headers property to see if the cookies are being included in the request headers. If they're not there, then there might be an issue with how the requests are being made or how the cookies are being set. For more detailed instructions and code examples, you can refer to the Next.js documentation on getServerSideProps (https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) and the cookie package documentation (https://www.npmjs.com/package/cookie). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai13mo ago
<@798450536004452392> kapa.ai is still learning and improving, please let us how it did by reacting below
optimistic-gold
optimistic-gold13mo ago
@kapa.ai Isn't it a bit strange that after succesful login using the supabase client. The auth provider works fine for client side but does not on server side ? As sson as the user is logged in, I can see that it fills the local storage with credentials (token) but the cookies are behaving weirdly.
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, it can seem a bit strange, but it's important to understand the differences between client-side and server-side environments. The Supabase client is designed to work in a browser environment, where it has access to the window object and can use it to store session data in local storage. This is why it works fine on the client-side. On the server-side, however, there is no window object, and the Supabase client doesn't have access to local storage. This is why it can't retrieve the session data on the server-side. As for the cookies, they are httpOnly, which means they can't be accessed through JavaScript. They are only sent with HTTP requests to the server. This is a security feature to prevent sensitive data from being exposed to client-side scripts. If you're seeing the cookies being set in the browser but not being sent with the requests to the server, it could be due to a few reasons: 1. The cookies are not being sent with the request. This could be because the request is not being made from the same domain that the cookies are set on. Cookies are only sent with requests that are made to the same domain. Make sure your server-side code is running on the same domain that your client-side code is running on. 2. The cookies are being blocked by the browser. Some browsers block third-party cookies by default. Make sure your browser settings allow third-party cookies. 3. The cookies are not being set correctly. Make sure the signInWithOAuth method is being called correctly and is successfully setting the cookies. If you're still having trouble, you might want to consider using a different method for server-side authentication. One common method is to use a JWT (JSON Web Token) that is stored in a secure httpOnly cookie. The JWT can be set by your server after successful authentication and then sent with every request to the server. Unfortunately, the provided extracts do not contain specific code examples or instructions for implementing this method with Supabase and refine. For more detailed instructions and code examples, you can refer to the Supabase documentation on server-side rendering (https://supabase.io/docs/guides/with-nextjs). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai13mo ago
<@798450536004452392> kapa.ai is still learning and improving, please let us how it did by reacting below
optimistic-gold
optimistic-gold13mo ago
@kapa.ai I am following some supabase documentation, I have setup a route in 'pages/auth/callback' but it also redirects me to login. How to disable authentication on this route?
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books: @kunalvirk That's a great question, but unfortunately I am only capable of responding to a maximum of three questions per thread. Don't hesitate to create a new thread for any further questions you have though. I'm here to help!