Benjythebee
Benjythebee

Reputation: 99

How to make custom jwt auth work on Supabase?

I need help setting up custom auth with RLS on Supabase and NextJS;

I used the following tutorial to get me started but I quickly realized it was outdated.

I'm stuck at generating a JWT and starting a session for a user given that JWT. Since the removal of auth.setAuth() I'm not too sure how to achieve my end goal in nextJS.

I have a public.users table with an id column which is a foreign key duplicate of the id column of auth.users. RLS is enabled and with the following UPDATE check: (auth.uid() = id).

NOTE: this is a duplicate of a post I made on Github, I'm hoping to get more answers on SO... https://github.com/orgs/supabase/discussions/15612#discussioncomment-6396134

The documentation on the feature is pretty confusing so I'm hoping that my post helps someone else as confused as me;

Here is my code:

/api/auth/login.ts (simplified for readability)

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const { email } = req.body

 // createPagesServerClient is from supabase's auth-helpers modules.
    const supabaseServerClient = createPagesServerClient({
        req,
        res,
    });
         // getUserByEmail retrieves user by email from table 'public.users'
        let user = await getUserByEmail(email, supabaseServerClient);
       if(user){ // User already exists at this point
        const newSecret = generateSecret();  // generats a random string
        const token = genCookie(user,req,res) // See function genCookie below (generates the JWT)

        supabaseServerClient.functions.setAuth(token)
        supabaseServerClient.realtime.setAuth(token)

        const {data:users,error} = await supabase
             .from("users") // public.users table
               .update({secret: newSecret })
                 .eq("email", email)
                .select();
        if(!user){
            return res.status(422).json({ error: "Could not update user " + reconstructedAddress});
        }
           return res.send(users[0])
     }else{
      // error
     }
}

function genCookie()

const genCookie = (user:SupabaseUser,req:IncomingMessage,res:ServerResponse)=>{
    const token = jwt.sign({ id:user.id, email:user.email }, process.env.JWT_SECRET ); //JWT_SECRET is from the supabase dashboard

// user j4w8n from github suggested using `sub: user.id` instead of id, however this also didn't work...

    return token
}

My issue is that the policy check clearly doesn't work since the query below returns error = null and users= [] (yet the user exists). So I assume my understanding of auth is completely wrong.

               const {data:users,error} = await supabase
             .from("users") // public.users table
               .update({secret: newSecret })
                 .eq("email", email)
                .select();

I'm really confused at how I can make auth work with custom jwt... I'd love some guidance. Also worth noting, I am using NextJS pages directory (not App directory);

    "@supabase/auth-helpers-nextjs": "^0.7.2",
    "@supabase/auth-helpers-react": "^0.4.0",
    "@supabase/supabase-js": "^2.24.0",

Upvotes: 3

Views: 4653

Answers (1)

Benjythebee
Benjythebee

Reputation: 99

Ok, I've found a partial solution, it looks like the auth-helper module needs to be updated so that the rest headers are also updated;

I changed my code to add a one-line hack:

supabaseServerClient.functions.setAuth(token)
supabaseServerClient.realtime.setAuth(token)
;(supabaseServerClient as any).rest.headers.Authorization = `Bearer ${token}`

and now I can successfully edit the user data;

However I'm still not sure how to create a session with that jwt EDIT: (see my comment I figured it out)

Upvotes: 2

Related Questions