extended-salmon
extended-salmon16mo ago

Refine/Next/Mantine/Supabase - access to register/forgot password page not allowed

While not logged in, the register/forgot password pages are not accessible. I get the unauthenticated redirect to login?to=%2Fregister. Expected behaviour, visitor should be able to register a new account while not authenticated.
"dependencies": { "@pankod/refine-cli": "^1.13.0", "@pankod/refine-core": "^3.90.4", "@pankod/refine-nextjs-router": "^4.1.0", "@pankod/refine-inferencer": "^2.0.2", "next": "^13.0.6", "next-compose-plugins": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "@pankod/refine-supabase": "^4.1.0", "nookies": "^2.5.2", "@pankod/refine-mantine": "^1.2.0", "@pankod/refine-react-table": "^4.7.2", "@tabler/icons": "^1.39.1", "@mantine/next": "^5.5.1", "@emotion/react": "^11.10.4", "@emotion/server": "^11.10.0", "@pankod/refine-kbar": "^0.8.0" },
"dependencies": { "@pankod/refine-cli": "^1.13.0", "@pankod/refine-core": "^3.90.4", "@pankod/refine-nextjs-router": "^4.1.0", "@pankod/refine-inferencer": "^2.0.2", "next": "^13.0.6", "next-compose-plugins": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "@pankod/refine-supabase": "^4.1.0", "nookies": "^2.5.2", "@pankod/refine-mantine": "^1.2.0", "@pankod/refine-react-table": "^4.7.2", "@tabler/icons": "^1.39.1", "@mantine/next": "^5.5.1", "@emotion/react": "^11.10.4", "@emotion/server": "^11.10.0", "@pankod/refine-kbar": "^0.8.0" },
Browser console gives 401 error from supabase.
{
"code": 401,
"msg": "invalid claim: missing sub claim"
}
{
"code": 401,
"msg": "invalid claim: missing sub claim"
}
40 Replies
refine-support-bot
Hi, I am refine support bot :wave:. I am here to help you with your question. I searched for the answer to your question in the refine documentation and found an answer! 🏆
Answer: The code snippet provided shows how to override the login page to allow login with email. SOURCES: ./docs/advanced-tutorials/data-provider/appwrite.md

Note: If this is the answer you need, then we are very lucky. If not, please wait for someone from the refine core team or the community to try to help you.
extended-salmon
extended-salmon16mo ago
Popup message is AuthApiError
adverse-sapphire
adverse-sapphire16mo ago
Hi @Devious, By default, the user will be redirected to /login if the checkAuth method rejects the Promise. Do you to redirect other page ? if you want, you can use this.
const authProvider: AuthProvider = {
...
checkAuth: () => {
...
return Promise.reject({
redirectPath: "/custom-page",
});
}
}
const authProvider: AuthProvider = {
...
checkAuth: () => {
...
return Promise.reject({
redirectPath: "/custom-page",
});
}
}
you can read this for more information: https://refine.dev/docs/tutorial/understanding-authprovider/create-authprovider/#checkauth
extended-salmon
extended-salmon16mo ago
I just want to go to /register, which I thought would work in default (it did when I tested antd).
adverse-sapphire
adverse-sapphire16mo ago
what was your authProvider implementation ? antd shouldn't related to this 🤔
extended-salmon
extended-salmon16mo ago
Default at the moment
import React from "react";import { AppProps } from "next/app";import { Refine } from "@pankod/refine-core";import { AuthPage, NotificationsProvider, notificationProvider, MantineProvider, Global, LightTheme, ReadyPage, ErrorComponent,} from "@pankod/refine-mantine";import routerProvider from "@pankod/refine-nextjs-router";import { dataProvider } from "@pankod/refine-supabase";import { MantineInferencer } from "@pankod/refine-inferencer/mantine";import { RefineKbarProvider } from "@pankod/refine-kbar";import { authProvider } from "src/authProvider";import { supabaseClient } from "src/utility";import { Title, Sider, Layout, Header } from "@components/layout";import { OffLayoutArea } from "@components/offLayoutArea";function MyApp({ Component, pageProps }: AppProps): JSX.Element { return ( <MantineProvider theme={LightTheme} withNormalizeCSS withGlobalStyles> <Global styles={{ body: { WebkitFontSmoothing: "auto" } }} /> <NotificationsProvider position="bottom-right"> <RefineKbarProvider> <Refine routerProvider={routerProvider} dataProvider={dataProvider(supabaseClient)} authProvider={authProvider} LoginPage={AuthPage} notificationProvider={notificationProvider} ReadyPage={ReadyPage} catchAll={<ErrorComponent />} resources={[ { name: "posts", list: MantineInferencer, edit: MantineInferencer, show: MantineInferencer, create: MantineInferencer, canDelete: true, }, ]} Title={Title} Sider={Sider} Layout={Layout} Header={Header} OffLayoutArea={OffLayoutArea} > <Component {...pageProps} /> </Refine> </RefineKbarProvider> </NotificationsProvider> </MantineProvider> );}export default MyApp;
import React from "react";import { AppProps } from "next/app";import { Refine } from "@pankod/refine-core";import { AuthPage, NotificationsProvider, notificationProvider, MantineProvider, Global, LightTheme, ReadyPage, ErrorComponent,} from "@pankod/refine-mantine";import routerProvider from "@pankod/refine-nextjs-router";import { dataProvider } from "@pankod/refine-supabase";import { MantineInferencer } from "@pankod/refine-inferencer/mantine";import { RefineKbarProvider } from "@pankod/refine-kbar";import { authProvider } from "src/authProvider";import { supabaseClient } from "src/utility";import { Title, Sider, Layout, Header } from "@components/layout";import { OffLayoutArea } from "@components/offLayoutArea";function MyApp({ Component, pageProps }: AppProps): JSX.Element { return ( <MantineProvider theme={LightTheme} withNormalizeCSS withGlobalStyles> <Global styles={{ body: { WebkitFontSmoothing: "auto" } }} /> <NotificationsProvider position="bottom-right"> <RefineKbarProvider> <Refine routerProvider={routerProvider} dataProvider={dataProvider(supabaseClient)} authProvider={authProvider} LoginPage={AuthPage} notificationProvider={notificationProvider} ReadyPage={ReadyPage} catchAll={<ErrorComponent />} resources={[ { name: "posts", list: MantineInferencer, edit: MantineInferencer, show: MantineInferencer, create: MantineInferencer, canDelete: true, }, ]} Title={Title} Sider={Sider} Layout={Layout} Header={Header} OffLayoutArea={OffLayoutArea} > <Component {...pageProps} /> </Refine> </RefineKbarProvider> </NotificationsProvider> </MantineProvider> );}export default MyApp;
oh, that posted badly
adverse-sapphire
adverse-sapphire16mo ago
i handled with prettier. its okay
extended-salmon
extended-salmon16mo ago
import { AuthProvider } from "@pankod/refine-core";import nookies from "nookies";import { supabaseClient } from "./utility";export const authProvider: AuthProvider = { login: async ({ email, password }) => { const { data, error } = await supabaseClient.auth.signInWithPassword({ email, password, }); if (error) { return Promise.reject(error); } if (data?.session) { nookies.set(null, "token", data.session.access_token, { maxAge: 30 * 24 * 60 * 60, path: "/", }); return Promise.resolve(); } // for third-party login return Promise.resolve(false); }, logout: async () => { nookies.destroy(null, "token"); const { error } = await supabaseClient.auth.signOut(); if (error) { return Promise.reject(error); } return Promise.resolve("/"); }, checkError: () => Promise.resolve(), checkAuth: async (ctx) => { const { token } = nookies.get(ctx); const { data } = await supabaseClient.auth.getUser(token); const { user } = data; if (user) { return Promise.resolve(); } return Promise.reject(); }, getPermissions: async () => { const user = await supabaseClient.auth.getUser(); if (user) { return Promise.resolve(user.data.user?.role); } }, getUserIdentity: async () => { const { data } = await supabaseClient.auth.getUser(); if (data?.user) { return Promise.resolve({ ...data.user, name: data.user.email, }); } },};
import { AuthProvider } from "@pankod/refine-core";import nookies from "nookies";import { supabaseClient } from "./utility";export const authProvider: AuthProvider = { login: async ({ email, password }) => { const { data, error } = await supabaseClient.auth.signInWithPassword({ email, password, }); if (error) { return Promise.reject(error); } if (data?.session) { nookies.set(null, "token", data.session.access_token, { maxAge: 30 * 24 * 60 * 60, path: "/", }); return Promise.resolve(); } // for third-party login return Promise.resolve(false); }, logout: async () => { nookies.destroy(null, "token"); const { error } = await supabaseClient.auth.signOut(); if (error) { return Promise.reject(error); } return Promise.resolve("/"); }, checkError: () => Promise.resolve(), checkAuth: async (ctx) => { const { token } = nookies.get(ctx); const { data } = await supabaseClient.auth.getUser(token); const { user } = data; if (user) { return Promise.resolve(); } return Promise.reject(); }, getPermissions: async () => { const user = await supabaseClient.auth.getUser(); if (user) { return Promise.resolve(user.data.user?.role); } }, getUserIdentity: async () => { const { data } = await supabaseClient.auth.getUser(); if (data?.user) { return Promise.resolve({ ...data.user, name: data.user.email, }); } },};
I referred to antd because I ran the create with antd to check if it was mantine specific and it worked.
extended-salmon
extended-salmon16mo ago
Logs from supabase
No description
adverse-sapphire
adverse-sapphire16mo ago
UI packages do not matter for this. but examples from refine may difference. you can use this to go register page when authentication not resolved
checkAuth: async () => {
const { data } = await supabaseClient.auth.getSession();
const { session } = data;

if (!session) {
return Promise.reject({
redirectPath: "/register",
});
}

return Promise.resolve();
},
checkAuth: async () => {
const { data } = await supabaseClient.auth.getSession();
const { session } = data;

if (!session) {
return Promise.reject({
redirectPath: "/register",
});
}

return Promise.resolve();
},
extended-salmon
extended-salmon16mo ago
Will that not always redirect to register though?
adverse-sapphire
adverse-sapphire16mo ago
yes it will
extended-salmon
extended-salmon16mo ago
So i would think expected behaviour would be as follows: no session -> login click register on login page -> /register click forgot-password on login page -> /forgot-password
adverse-sapphire
adverse-sapphire16mo ago
Sorry, I couldn't follow exactly. What was the problem in implementing this business logic?
extended-salmon
extended-salmon16mo ago
The links on the login page do not redirect to /register when there is no session active
adverse-sapphire
adverse-sapphire16mo ago
do you have /pages/register.tsx ?
extended-salmon
extended-salmon16mo ago
Here: https://dev.sapphirecrm.io Exposed local env I swizzled the auth components from mantine so I get the authpage from import { AuthPage } from "@components/pages/auth"; Yes I have them loaded
extended-salmon
extended-salmon16mo ago
this is on next.js
No description
extended-salmon
extended-salmon16mo ago
import React from "react";import { useAuthenticated, useNavigation, useRouterContext,} from "@pankod/refine-core";export type AuthenticatedProps = { /** * Content to show if user is not logged in. If undefined, routes to `/` */ fallback?: React.ReactNode; /** * Content to show while checking whether user is logged in */ loading?: React.ReactNode; children: React.ReactNode;};/** * `<Authenticated>` is the component form of {@link https://refine.dev/docs/core/hooks/auth/useAuthenticated `useAuthenticated`}. It internally uses `useAuthenticated` to provide it's functionality. * * @see {@link https://refine.dev/docs/core/components/auth/authenticated `<Authenticated>`} component for more details. */export const Authenticated: React.FC<AuthenticatedProps> = ({ children, fallback, loading,}) => { const { isSuccess, isLoading, isError } = useAuthenticated(); const { replace } = useNavigation(); const { useLocation } = useRouterContext(); const { pathname, search } = useLocation(); if (isLoading) { return <>{loading}</> || null; } if (isError) { if (!fallback) { const toURL = `${pathname}${search}`; if (!pathname.includes("/login")) { replace(`/login?to=${encodeURIComponent(toURL)}`); } return null; } return <>{fallback}</>; } if (isSuccess) { return <>{children}</>; } return null;};
import React from "react";import { useAuthenticated, useNavigation, useRouterContext,} from "@pankod/refine-core";export type AuthenticatedProps = { /** * Content to show if user is not logged in. If undefined, routes to `/` */ fallback?: React.ReactNode; /** * Content to show while checking whether user is logged in */ loading?: React.ReactNode; children: React.ReactNode;};/** * `<Authenticated>` is the component form of {@link https://refine.dev/docs/core/hooks/auth/useAuthenticated `useAuthenticated`}. It internally uses `useAuthenticated` to provide it's functionality. * * @see {@link https://refine.dev/docs/core/components/auth/authenticated `<Authenticated>`} component for more details. */export const Authenticated: React.FC<AuthenticatedProps> = ({ children, fallback, loading,}) => { const { isSuccess, isLoading, isError } = useAuthenticated(); const { replace } = useNavigation(); const { useLocation } = useRouterContext(); const { pathname, search } = useLocation(); if (isLoading) { return <>{loading}</> || null; } if (isError) { if (!fallback) { const toURL = `${pathname}${search}`; if (!pathname.includes("/login")) { replace(`/login?to=${encodeURIComponent(toURL)}`); } return null; } return <>{fallback}</>; } if (isSuccess) { return <>{children}</>; } return null;};
This is the default authenticated.tsx page when I swizzle it
adverse-sapphire
adverse-sapphire16mo ago
I believe i understand. nextjs makes routing from file system. and refine detects this with pages/[[...refine]].tsx. its quite diffrence from react-router. I think this needs to be emphasized in the docs. I'll add this to our backlog and try to prioritize to avoid confusions in the future. if you move your register.tsx to pages/register.tsx probably problem will solve or you can move pages/register/index.tsx of course
extended-salmon
extended-salmon16mo ago
let me try That is strange though, because login.tsx from src/components/pages/auth/components works This is the index.tsx from the auth folder
import React from "react";import { AuthPageProps } from "@pankod/refine-core";import { BoxProps, CardProps } from "@pankod/refine-mantine";import { LoginPage, RegisterPage, ForgotPasswordPage, UpdatePasswordPage,} from "./components";import { UseFormInput } from "@mantine/form/lib/types";export type FormPropsType = UseFormInput<unknown> & { onSubmit?: (values: any) => void;};export type AuthProps = AuthPageProps<BoxProps, CardProps, FormPropsType>;/** * **refine** has a default auth page form served on the `/login` route when the `authProvider` configuration is provided. * @see {@link https://refine.dev/docs/api-reference/mantine/components/mantine-auth-page/} for more details. */export const AuthPage: React.FC<AuthProps> = (props) => { const { type } = props; const renderView = () => { switch (type) { case "register": return <RegisterPage {...props} />; case "forgotPassword": return <ForgotPasswordPage {...props} />; case "updatePassword": return <UpdatePasswordPage {...props} />; default: return <LoginPage {...props} />; } }; return <>{renderView()}</>;};
import React from "react";import { AuthPageProps } from "@pankod/refine-core";import { BoxProps, CardProps } from "@pankod/refine-mantine";import { LoginPage, RegisterPage, ForgotPasswordPage, UpdatePasswordPage,} from "./components";import { UseFormInput } from "@mantine/form/lib/types";export type FormPropsType = UseFormInput<unknown> & { onSubmit?: (values: any) => void;};export type AuthProps = AuthPageProps<BoxProps, CardProps, FormPropsType>;/** * **refine** has a default auth page form served on the `/login` route when the `authProvider` configuration is provided. * @see {@link https://refine.dev/docs/api-reference/mantine/components/mantine-auth-page/} for more details. */export const AuthPage: React.FC<AuthProps> = (props) => { const { type } = props; const renderView = () => { switch (type) { case "register": return <RegisterPage {...props} />; case "forgotPassword": return <ForgotPasswordPage {...props} />; case "updatePassword": return <UpdatePasswordPage {...props} />; default: return <LoginPage {...props} />; } }; return <>{renderView()}</>;};
adverse-sapphire
adverse-sapphire16mo ago
actually, you are right we will consider this
extended-salmon
extended-salmon16mo ago
Perhaps I will remake with cra instead
adverse-sapphire
adverse-sapphire16mo ago
we think this is confusing too. we have plan to simplify this on refine v4
extended-salmon
extended-salmon16mo ago
I kind of wanted to make use of ssr on next though I can try remix too to see if the behaviour is the same
adverse-sapphire
adverse-sapphire16mo ago
is /register now working ?
extended-salmon
extended-salmon16mo ago
I need to rejig as when I moved the auth folder to pages, and updated imports it broke No, it still isn't working
import { AuthPage } from "pages/auth";
import { AuthPage } from "pages/auth";
extended-salmon
extended-salmon16mo ago
No description
metropolitan-bronze
metropolitan-bronze16mo ago
Hey @Devious, Next.js and Remix use file-system based routing. Initially in Next.js it's the /pages directory and its content. When you create a Refine app using create-refine-app, it will create a route under /pages with name [[...refine]].tsx which is used to render resource pages/actions. Such as, if you define a posts resource with list: PostList component, then [[...refine]].tsx route will be used to render the PostList component under /posts ([[...refine]].tsx route is an optional catch-all route, which means you can define posts.tsx file under /pages and handle the rendering of the page yourself. An optional catch-all route won't be rendered if there's a more specific route defined in /pages) When you're using an authProvider, refine will handle the /login route for you, since its the default route we redirect after failed attempts to the authorized routes (such as resource routes created from the resources prop) But the other pages such as /register or /forgot-password are not created by refine. We provide the <AuthPage /> component as an helper component, so you can just plug it in, customize it as you like and it will do the communication with the authProvider you've passed to the <Refine /> component. When you see routes like /login?to=register it means, [[...refine]].tsx is used to render this /register route. Since we do checkAuth check in [[...refine]] page before rendering the resource components, /register is treated just like them. So when you navigate to /register refine will run checkAuth and since it rejects, refine will navigate to /login.
extended-salmon
extended-salmon16mo ago
I had to update the component imports as export * from ./register' is not allowed
metropolitan-bronze
metropolitan-bronze16mo ago
So as a solution, you need to define the /register route inside your /pages directory (not /src/pages or /src/components/pages) When you define the /register route, you can do simply;
export default function RegisterPage() {
return (
<AuthPage type="register" />
);
}
export default function RegisterPage() {
return (
<AuthPage type="register" />
);
}
So it will render the AuthPage in type register in that route. We need to admit that there's a gap in this part of the docs. We'll try our best to come up with a more detailed documentation about Authentication in Next.js and Remix since it's easy to mix the solutions of React Router v6 with these above. The update will happen in both refine's next.js docs and in auth provider sections of the tutorial so we won't make any misleads about those.
extended-salmon
extended-salmon16mo ago
Yeah, I am not completely following. as the auth/index.tsx has render components for register, forgot password and update password for props
extended-salmon
extended-salmon16mo ago
No description
extended-salmon
extended-salmon16mo ago
okay, it works when I make CRA with supabase Okay, I get it have it working
sensitive-blue
sensitive-blue16mo ago
@Devious if you don't mind, can you explain how this works? I don't want to start over and use CRA though so I'm kinda stuck on how to use the components given for the register page etc.
extended-salmon
extended-salmon16mo ago
Hmm @kitkatnik So because of the way routing works in remix/nextjs you need a component in the 'right' location which will essentially return the correct register/forgot password component.
extended-salmon
extended-salmon16mo ago
Something like this
No description
extended-salmon
extended-salmon16mo ago
Then in your login component, you have the links like this:
No description
extended-salmon
extended-salmon16mo ago
sorry, not a regular discord user, so only seeing your message now
sensitive-blue
sensitive-blue16mo ago
No worries! This is super helpful, I appreciate the visuals! 😄