deep-jade
deep-jade3y 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.
deep-jade
deep-jadeOP3y ago
Popup message is AuthApiError
rising-crimson
rising-crimson3y 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
deep-jade
deep-jadeOP3y ago
I just want to go to /register, which I thought would work in default (it did when I tested antd).
rising-crimson
rising-crimson3y ago
what was your authProvider implementation ? antd shouldn't related to this 🤔
deep-jade
deep-jadeOP3y 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
rising-crimson
rising-crimson3y ago
i handled with prettier. its okay
deep-jade
deep-jadeOP3y 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.
deep-jade
deep-jadeOP3y ago
Logs from supabase
No description
rising-crimson
rising-crimson3y 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();
},
deep-jade
deep-jadeOP3y ago
Will that not always redirect to register though?
rising-crimson
rising-crimson3y ago
yes it will
deep-jade
deep-jadeOP3y 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
rising-crimson
rising-crimson3y ago
Sorry, I couldn't follow exactly. What was the problem in implementing this business logic?
deep-jade
deep-jadeOP3y ago
The links on the login page do not redirect to /register when there is no session active
rising-crimson
rising-crimson3y ago
do you have /pages/register.tsx ?
deep-jade
deep-jadeOP3y 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
deep-jade
deep-jadeOP3y ago
this is on next.js
No description
deep-jade
deep-jadeOP3y 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
rising-crimson
rising-crimson3y 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
deep-jade
deep-jadeOP3y 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()}</>;};
rising-crimson
rising-crimson3y ago
actually, you are right we will consider this
deep-jade
deep-jadeOP3y ago
Perhaps I will remake with cra instead
rising-crimson
rising-crimson3y ago
we think this is confusing too. we have plan to simplify this on refine v4
deep-jade
deep-jadeOP3y 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
rising-crimson
rising-crimson3y ago
is /register now working ?
deep-jade
deep-jadeOP3y 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";
deep-jade
deep-jadeOP3y ago
No description
correct-apricot
correct-apricot3y 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.
deep-jade
deep-jadeOP3y ago
I had to update the component imports as export * from ./register' is not allowed
correct-apricot
correct-apricot3y 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.
deep-jade
deep-jadeOP3y ago
Yeah, I am not completely following. as the auth/index.tsx has render components for register, forgot password and update password for props
deep-jade
deep-jadeOP3y ago
No description
deep-jade
deep-jadeOP3y ago
okay, it works when I make CRA with supabase Okay, I get it have it working
boiling-coffee
boiling-coffee3y 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.
deep-jade
deep-jadeOP2y 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.
deep-jade
deep-jadeOP2y ago
Something like this
No description
deep-jade
deep-jadeOP2y ago
Then in your login component, you have the links like this:
No description
deep-jade
deep-jadeOP2y ago
sorry, not a regular discord user, so only seeing your message now
boiling-coffee
boiling-coffee2y ago
No worries! This is super helpful, I appreciate the visuals! 😄

Did you find this page helpful?