skip to Main Content

I’m having an issue when in my Next.js application when trying to fetch data via a route handler.

My database has a users table that contains an ID called user_id that matches the uid of the authenticated user, and aps_id which I use to make a call to a 3rd party API.

If I do not have RLS enabled on the table, I get the row returned as expected when I do a match for user ID.

If I have RLS enabled with the rule auth.uid() = user_id I get no rows returned.

I have the following code in my route handler:

route.ts

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function GET() {
    try {
        const supabase = createRouteHandlerClient({ cookies });

        const { data: userData } = await supabase.from('users').select('aps_id').single();
        const apsId = userData?.aps_id;
        const {
            data: { user },
        } = await supabase.auth.getUser();

        console.log(user); // no user being returned?


        const res = await fetch(process.env.APS_API_URL + 'ClientEligibility/' + apsId, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'apiKey': process.env.APS_API_KEY || ''
            }
        });
    
        const data = await res.json();

        console.log(data); // this is null, but it should be returning a row?
    
        return NextResponse.json({ data });
    } catch(e) {
        console.error(e);

        return NextResponse.json({ error: e }, { status: 500 });
    }
}

It seems like there’s no user session data coming back, so I assume auth.uid() in the RLS policy is also resulting in null.

Is there another necessary step required to get the user session in a route handler?

If I do not have RLS enabled on the table, I get the row returned as expected when I do a match for user ID.
If I have RLS enabled with the rule auth.uid() = user_id I get no rows returned.

2

Answers


  1. Chosen as BEST ANSWER

    I found an article by Jon Meyers at Supabase shortly after posting this which explains the issue (not really an issue, but intented behavior):

    https://jonmeyers.io/blog/forwarding-cookies-from-server-components-to-route-handlers-with-next-js-app-router

    TL;DR: manually add headers to your fetch request using next/headers:

    import { headers } from "next/headers";
    
    export default async function Page() {
      await fetch("http://localhost:3000/test", {
        headers: headers(),
      });
    
      return ...
    }
    

  2. The Row-Level Security (RLS) issue in your Next.js application may be remedied by ensuring that you are fully authorized before accessing the protected resources in the Supabase database. You are attempting to get data from your Supabase database in your code. This implies that you must ensure that the user is authorized and that the authentication token is given to Supabase along with the request. Before visiting the route, ensure that your users are properly authorized. Using Supabase’s authentication library, you should determine if the user is authenticated. When sending a request to your Next.js route handler, include the authentication token in the request.

    export async function GET({ request }) {
        try {
            // Check if the user is authenticated
            const user = await supabase.auth.api.getUserByCookie(request);
    
            if (!user) {
                // Handle unauthenticated user (e.g., return an error response)
                return NextResponse.error('Not authenticated', { status: 401 });
            }
    
            // Now that the user is authenticated, get the UID
            const uid = user.id;
    
            const supabase = createRouteHandlerClient({ cookies });
    
            const { data: userData } = await supabase
                .from('users')
                .select('aps_id')
                .eq('user_id', uid) // Filter by the authenticated user's UID
                .single();
    
            const apsId = userData?.aps_id;
    
            // Proceed with the rest of your code, including the fetch request to the API
    
            // ...
    
            return NextResponse.json({ data });
        } catch (e) {
            console.error(e);
            return NextResponse.json({ error: e }, { status: 500 });
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search