One of the core things that people need to have is a public profile. The standard way is to create a profiles
table. Your version of Supabase may do this automatically. It also depends on what login authentication methods you are using.
Users Private Schema#
- When you create a user, your auth schema saves the data. Each individual login identity (google, apple, email...) along with the UUID is saved in the
identities
database. - Your user meta data from your authentication method is saved under
users.raw_user_meta_data
, and your provider methods are saved underusers.raw_app_meta_data
.
Methods#
Each method may have different options that are returned. The oAuth methods differ. Google will return your photo url as well as your name. Twitter may return your username. All of this is stored as JSON data in the raw-user_meta_data
column.
Client#
You can access this data on the frontend by:
supabase.auth.getUser();
or
supabase.auth.getSession().then(session => session ? session.data.session?.user : null);
But you can also update that data. Your original methods will still be saved.
Update Data Methods#
Add a key#
Put the key(s) with in the data
object.
supabase.auth.updateUser({
data: {
avatar_url: 'https://...'
}
});
The data object will save each individual key / value to the raw_user_meta_data JSON. It DOES NOT replace the entire JSON data, but only the key(s) you enter.
Remove a key#
Set the key(s) to null you want to remove.
supabase.auth.updateUser({
data: {
avatar_url: null
}
});
But how do you grab this data for your profiles
table?
Method 1 - Trigger Function#
CREATE OR REPLACE FUNCTION create_profile()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO profile (id, display_name)
VALUES (
NEW.id,
NEW.raw_user_meta_data ->> 'user_name'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
If you want the avatar_url
, then do:
INSERT INTO profile (id, avatar_url)
VALUES (
NEW.id,
NEW.raw_user_meta_data ->> 'avatar_url'
);
This will make sure the data is inserted on creation.
But what about the front end methods?
Method 2 - onAuthStateChange#
You want to check that the user exists, then add it IFF it does not exist. I did not use await
here since it is in a subscribing observable-like function.
Check User#
const checkUser = (user: User): void => {
// check for public profile record or create one
supabase.from('profiles').select('*').eq('id', user.id)
.then(({ data, error }) => {
if (error) {
console.error(error);
}
if (data.length === 0) {
supabase.from('profiles').insert({
photo_url: user.user_metadata.avatar_url || null,
display_name: user.user_metadata.full_name || null
}).then(({ error }) => {
if (error) {
console.error(error);
}
});
}
});
}
Note: The full_name
and avatar_url
are usually only available on Google Authentication.
Look for changes#
You can use onAuthStateChange
, or my simplified version:
npm i j-supabase
import { authUser } from 'j-supabase';
...
authUser(supabase).subscribe(user => {
if (user) {
checkUser(user);
// ... then set user in store, hook, observable, or service
}
});
For more on j-supabase
What content do I need?#
You don't want to copy all of the content. You only want to copy PUBLIC content. The user's email is already in the database and is not public, so you probably would not want to add that. A username, profile image, full name, etc. would be public information.
If your app allows a user to upload their own profile image, you would want to change it in TWO places. You want to change the public profile image, and their stored image using the updateUser()
method above.
See my article on Firebase Authentication, and you will see you can create a user almost exactly the same way.
J