This package provide a dataProvider, an authProvider and hooks to integrate [Supabase](https://supabase.io/) with [ra-core](https://marmelab.com/ra-core/).
npm install ra-supabase-coreThis package provide a dataProvider, an authProvider and hooks to integrate Supabase with ra-core.
``sh`
yarn add ra-supabase-coreor
npm install ra-supabase-core
`jsx
// 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-core';
import { supabase } from './supabase';
export const dataProvider = supabaseDataProvider({
instanceUrl: 'YOUR_SUPABASE_URL',
apiKey: 'YOUR_SUPABASE_ANON_KEY',
supabase
});
// in authProvider.js
import { supabaseAuthProvider } from 'ra-supabase-core';
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, Resource, ListGuesser } from 'react-admin';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
export const MyAdmin = () => (
);
`
ra-supabase is built on ra-data-postgrest that leverages PostgREST. As such, you have access the following features:
#### Filters operators
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:
`jsx
const postFilters = [
];
export const PostList = () => (
...
);
`
See the PostgREST documentation for a list of supported operators.
#### RLS
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.
#### Customizing the dataProvider
supabaseDataProvider also accepts the same options as the ra-data-postgrest dataProvider (except apiUrl), like primaryKeys or schema.
`jsx
// 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.
#### Email & Password Authentication
To login users using their email and password, call the login method returned by the useLogin hook with the user credentials as an object:
`jsx
import { useLogin } from 'react-admin';
const myLoginForm = () => {
const login = useLogin();
const redirectTo = window.location.toString();
const handleSubmit = (event) => {
login({
email: event.target.email.value,
password: event.target.password.value,
}, redirectTo);
}
return (
#### OAuth Authentication
To login users using the OAuth providers enabled on your Supabase instance, call the
login method returned by the useLogin hook with an object containing the provider name:`jsx
import { useLogin } from 'react-admin';const myLoginForm = () => {
const login = useLogin();
const loginWith = (provider) => {
const redirectTo = window.location.toString();
login({ provider, options: { redirectTo }).catch(
error => {
// The authProvide always reject for OAuth login but there will be no error
// if the call actually succeeds. This is to avoid react-admin redirecting
// immediately to the provided redirect prop before users are redirected to
// the OAuth provider.
if (error) {
notify((error as Error).message, { type: 'error' });
}
}
);
}
return (
)
}
`Make sure you enabled the specified providers in your Supabase instance:
- Hosted instance
- Local instance
API
$3
The
supabaseDataProvider leverages ra-data-postgrest. Please refer to their documentation to know how to use it.$3
The
supabaseAuthProvider must be initialized with your supabase client and an optional function to call when we need to display the user identity. Here's an example that fetches the user identity from a userProfiles table:`jsx
// in authProvider.js
import { supabaseAuthProvider } from 'ra-supabase-core';
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},
};
},
});
`The
supabaseAuthProvider supports an optional getpermissions method that allows you to fetch user permissions. Here's an example that fetches user permissions from a userPermissions table. You can then use the usePermissions hook to retrieve them later.`jsx
// in authProvider.js
import { supabaseAuthProvider } from 'ra-supabase-core';
import { supabase } from './supabase';export const authProvider = supabaseAuthProvider(supabase, {
getPermissions: async user => {
const { data, error } = await supabase
.from('userPermissions')
.select('id, can_edit')
.match({ email: user.email })
.single();
if (!data || error) {
throw new Error();
}
return {
id: data.id,
canEdit: data.can_edit,
};
},
});
`supabaseAuthProvider also provides an additional setPassword method. This method allows you to create UI for users to set their passwords after being invited for example. This could be done in a custom route. The method signature is the following:setPassword({ access_token: string; password: string }): Promise$3
This hook returns the access token for the current user from the URL and redirects the user to the home page if no access token is found. The redirection url can be overridden or disabled. The name of the
access token parameter to look for in the URL can also be overridden (
access_token by default).This is useful in pages related to authentication such as one which would allow invited users to set their password.
`jsx
import { useSupabaseAccessToken } from 'ra-supabase-core';const SetPasswordPage = () => {
const access_token = useSupabaseAccessToken();
// Logic and UI to set the user password
};
`$3
This hook returns a function you can call to set the current user password. The function requires the user access token. The hook accept an option object with the following optional properties:
-
onSuccess: A function called when the set password operation succeeds. By default, it redirects users to the home page.
- onFailure: A function called when the set password operation fails. By default, it display an error notification.`jsx
import { useSupabaseAccessToken } from 'ra-supabase-core';const SetPasswordPage = () => {
const access_token = useSupabaseAccessToken();
const setPassword = useSetPassword();
const handleSubmit = event => {
setPassword({
access_token,
password: event.currentTarget.elements.password.value,
});
};
return (
);
};
`$3
This hooks checks whether users are authenticated and redirect them to the provided route (which defaults to the home page) when they are.
This is useful inside a custom login page and is the behavior of react-admin default login page, extracted as a hook.
`jsx
import { useRedirectIfAuthenticated } from 'react-admin';
const MyLoginPage = () => {
useRedirectIfAuthenticated(); // UI and logic for authentication
};
``- Add support for magic link authentication