How can I update a user's metadata as an admin? I ...
# off-topic
k
How can I update a user's metadata as an admin? I don't see anything about this in the docs. Presumably, the supabase.auth.update() only works when the user is logged in: https://supabase.io/docs/reference/javascript/auth-update
j
you can create a new table, maybe something like
profiles
which can contain whatever user metadata you like. could also add a enum type for the user_status column
Copy code
sql

CREATE TYPE user_status AS ENUM ('trialing', 'active', 'cancelled');

CREATE TABLE profiles (
  id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  -- foreign key that uses auth.users, so the UUID here has to match one of your users
  user_id uuid REFERENCES auth.users NOT NULL,
  inserted_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL,
  updated_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL,
  -- column for user_status, using the enum type made above
  user_status user_status DEFAULT 'active'
)
k
Thanks, yes I am already doing that
but doing this requires two steps in order to check the status of the user
the first calls supabase to fetch the user, but then a second step is required to fetch the info from the other profiles table
I was hoping that I could include this information in the initial auth response, such as by having it in the metadata, but then I need a way to update this data programmatically
j
Not sure then - I originally thought you could expose the
auth
schema in your api, but I think that schema is protected. Then you could of queried a foreign table at the same time as
auth.users
I think there was some good reasons, mostly security, as to why the auth.users table is locked up and not exposed though - and possibly some reasoning why we encourage you to keep user meta data in another table - i'll ask around. its an interesting use case 🙂
k
alright, thanks for your help 🙂
r
hi @User ! wanting to do the exact same thing ... did you figure this out?
looked into the GoTrue repo and there is an admin API you can use ... this worked for me:
Copy code
import { NextApiRequest, NextApiResponse } from "next"

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    if (req.method === "PATCH") {
      const { userId } = req.query
      const { appMetadata } = req.body

      if (!appMetadata) {
        res.status(400).json({ error: "Missing appMetadata" })
        return
      }

      const url = `${process.env.NEXT_PUBLIC_SUPABASE_URL}/auth/v1/admin/users/${userId}`
      const options = {
        method: 'PUT',
        body: JSON.stringify({ app_metadata: appMetadata }),
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.SUPABASE_SERVICE_KEY}`,
          'apikey': process.env.SUPABASE_SERVICE_KEY,
        }
      }
      const result = await fetch(url, options)
        .then(res => res.json())
      
      res.status(200).json({ user: result })
    } else {
      res.status(405).json({ error: 'Method not allowed' })
    }
  } catch (error) {
    res.status(500).json({ error: error.message || JSON.stringify(error) })
  }
}
basically hosting that on my app: PATCH /api/private-protected-admin-endpoints/users/{id}
it's kind of weird how it needs two headers for auth, but one is for supabase's API wrapper and the oher one for actual GoTrue's api
needless to say this has to be called from a protected endpoint since it's using supabase's service api key
j
proceed with caution with the above. I'm not 100% certain but the above could possibly break some supabase auth features depending what is in the body of that fetch
cc @User - some interesting use cases here for updating user meta data on auth schema