This package provides a dataProvider, an authProvider, hooks and components to integrate Supabase with react-admin when using its default UI (ra-ui-materialui).
It leverages ra-supabase-core and ra-supabase-ui-materialui.
yarn add ra-supabase
# or
npm install ra-supabase
// in supabase.js
import { createClient } from '@supabase/supabase-js';
export const supabase = createClient('YOUR_SUPABASE_URL', 'YOUR_SUPABASE_ANON_KEY');
// in dataProvider.js
import { supabaseDataProvider } from 'ra-supabase';
import { supabaseClient } from './supabase';
export const dataProvider = supabaseDataProvider({
instanceUrl: 'YOUR_SUPABASE_URL',
apiKey: 'YOUR_SUPABASE_ANON_KEY',
supabaseClient
});
// in authProvider.js
import { supabaseAuthProvider } from 'ra-supabase';
import { supabase } from './supabase';
export const authProvider = supabaseAuthProvider(supabase, {
getIdentity: async user => {
const { data, error } = await supabase
.from('userProfiles')
.select('id, first_name, last_name')
.match({ email: user.email })
.single();
if (!data || error) {
throw new Error();
}
return {
id: data.id,
fullName: `${data.first_name} ${data.last_name}`,
};
},
});
// in App.js
import { Admin, CustomRoutes, Resource, ListGuesser } from 'react-admin';
import { LoginPage, SetPasswordPage, ForgotPasswordPage } from 'ra-supabase';
import { BrowserRouter, Route } from 'react-router-dom';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
<BrowserRouter>
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={LoginPage}
>
<CustomRoutes noLayout>
<Route
path={SetPasswordPage.path}
element={<SetPasswordPage />}
/>
<Route
path={ForgotPasswordPage.path}
element={<ForgotPasswordPage />}
/>
</CustomRoutes>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
</BrowserRouter>
);
You must wrap your <Admin>
inside a <BrowserRouter>
as supabase use hash parameters for passing authentication tokens.
ra-supabase
is built on ra-data-postgrest
that leverages PostgREST. As such, you have access the following features:
When specifying the source
prop of filter inputs, you can either set it to the field name for simple equality checks or add an operator suffix for more control. For instance, the gte
(Greater Than or Equal) or the ilike
(Case insensitive like) operators:
const postFilters = [
<TextInput label="Title" source="title@ilike" alwaysOn />,
<TextInput label="Views" source="views@gte" />,
];
export const PostList = () => (
<List filters={postFilters}>
...
</List>
);
See the PostgREST documentation for a list of supported operators.
As users authenticate through supabase, you can leverage Row Level Security. Users identity will be propagated through the dataProvider if you provided the public API (anon) key. Keep in mind that passing the service_role
key will bypass Row Level Security. This is not recommended.
supabaseDataProvider
also accepts the same options as the ra-data-postgrest
dataProvider (except apiUrl
), like primaryKeys
or schema
.
// in dataProvider.js
import { supabaseDataProvider } from 'ra-supabase-core';
import { supabaseClient } from './supabase';
export const dataProvider = supabaseDataProvider({
instanceUrl: 'YOUR_SUPABASE_URL',
apiKey: 'YOUR_SUPABASE_ANON_KEY',
supabaseClient,
primaryKeys: new Map([
['some_table', ['custom_id']],
['another_table', ['first_column', 'second_column']],
]),
schema: () => localStorage.getItem("schema") || "api",
});
See the `ra-data-postgrest`` documentation for more details.
ra-supabase
supports email/password and OAuth authentication.
To setup only the email/password authentication, just pass the LoginPage
to the loginPage
prop of the <Admin>
component:
import { Admin, Resource, ListGuesser } from 'react-admin';
import { LoginPage } from 'ra-supabase';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
<BrowserRouter>
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={LoginPage}
>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
</BrowserRouter>
);
ra-supabase
supports the invitation workflow. If a user is invited to use the application (by sending an invitation through Supabase dashboard for instance), you can configure the /set-password
custom route to allow them to set their password.
This requires you to configure your supabase instance:
- Go to your dashboard Authentication section
- In URL Configuration, set Site URL to your application URL
- In URL Configuration, add the following URL in the Redirect URLs section:
YOUR_APPLICATION_URL/auth-callback
- In Email Templates, change the
"{{ .ConfirmationURL }}"
to"{{ .ConfirmationURL }}/auth-callback"
You can now add the /set-password
custom route:
// in App.js
import { Admin, CustomRoutes, Resource, ListGuesser } from 'react-admin';
import { LoginPage, SetPasswordPage } from 'ra-supabase';
import { BrowserRouter, Route } from 'react-router-dom';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
<BrowserRouter>
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={LoginPage}
>
<CustomRoutes noLayout>
<Route
path={SetPasswordPage.path}
element={<SetPasswordPage />}
/>
</CustomRoutes>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
</BrowserRouter>
);
If users forgot their password, they can request for a reset if you add the /forgot-password
custom route. You should also set up the /set-password
custom route to allow them to choose their new password.
This requires you to configure your supabase instance:
- Go to your dashboard Authentication section
- In URL Configuration, set Site URL to your application URL
- In URL Configuration, add the following URL in the Redirect URLs section:
YOUR_APPLICATION_URL/auth-callback
- In Email Templates, change the
"{{ .ConfirmationURL }}"
to"{{ .ConfirmationURL }}/auth-callback"
You can now add the /forgot-password
and /set-password
custom routes:
// in App.js
import { Admin, CustomRoutes, Resource, ListGuesser } from 'react-admin';
import { LoginPage, SetPasswordPage, ForgotPasswordPage } from 'ra-supabase';
import { BrowserRouter, Route } from 'react-router-dom';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
<BrowserRouter>
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={LoginPage}
>
<CustomRoutes noLayout>
<Route
path={SetPasswordPage.path}
element={<SetPasswordPage />}
/>
<Route
path={ForgotPasswordPage.path}
element={<ForgotPasswordPage />}
/>
</CustomRoutes>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
</BrowserRouter>
);
To setup OAuth authentication, you can pass a LoginPage
element:
import { Admin, Resource, ListGuesser } from 'react-admin';
import { LoginPage } from 'ra-supabase';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
<BrowserRouter>
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={<LoginPage providers={['github', 'twitter']} />}
>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
</BrowserRouter>
);
Make sure you enabled the specified providers in your Supabase instance:
This also requires you to configure the redirect URLS on your supabase instance:
- Go to your dashboard Authentication section
- In URL Configuration, set Site URL to your application URL
- In URL Configuration, add the following URL in the Redirect URLs section:
YOUR_APPLICATION_URL/auth-callback
To disable email/password authentication, set the disableEmailPassword
prop:
import { Admin, Resource, ListGuesser } from 'react-admin';
import { LoginPage } from 'ra-supabase';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
loginPage={<LoginPage disableEmailPassword providers={['github', 'twitter']} />}
>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
);
We provide two language packages:
// in i18nProvider.js
import { mergeTranslations } from 'ra-core';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import frenchMessages from 'ra-language-french';
import { raSupabaseEnglishMessages } from 'ra-supabase-language-english';
import { raSupabaseFrenchMessages } from 'ra-supabase-language-french';
const allEnglishMessages = mergeTranslations(
englishMessages,
raSupabaseEnglishMessages
);
const allFrenchMessages = mergeTranslations(
frenchMessages,
raSupabaseFrenchMessages
);
export const i18nProvider = polyglotI18nProvider(
locale => (locale === 'fr' ? allFrenchMessages : allEnglishMessages),
'en'
);
// in App.js
import { Admin, Resource, ListGuesser } from 'react-admin';
import { LoginPage } from 'ra-supabase';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
import { i18nProvider } from './i18nProvider';
export const MyAdmin = () => (
<BrowserRouter>
<Admin
dataProvider={dataProvider}
authProvider={authProvider}
i18nProvider={i18nProvider}
loginPage={LoginPage}
>
<Resource name="posts" list={ListGuesser} />
<Resource name="authors" list={ListGuesser} />
</Admin>
</BrowserRouter>
);
- Add support for magic link authentication
- Add support for uploading files to Supabase storage