Next.js 프로젝트에 Supabase를 연동하다가 다음과 같은 오류가 나면 확인해보자:

Error: Failed to construct 'URL': Invalid URL

해당 오류 원인

  • .env.local 파일에 SUPABASE_URL이 다음과 같이 뛰어졌거나,
  • 정의되지 않은 변수(undefined)가 createClient()로 전달되면 개체 URL 처리에서 오류가 발생한다.

해결 방법

  • .env.local에 필요 값 설정
NEXT_PUBLIC_SUPABASE_URL=https://<your-project>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-anon-key>
  • 2. Supabase 컨솔 > Project Settings > API 화면에서 URL 및 anon key 복사

  • supabaseClient.js에 이름 및 예제 추가
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

if (!supabaseUrl || !supabaseAnonKey) {
  throw new Error("Supabase 환경 변수가 설정되지 않았습니다.");
}

export const supabase = createClient(supabaseUrl, supabaseAnonKey);
  • Next.js dev 서버 다시 시작
npm run dev

마무리 핀터

.env.local 변경 후에는

다시 시작 해야 한다! 그래야 변경된 환경변수가 반영된다.

'Back-End > Supabase' 카테고리의 다른 글

Supabase에서의 RLS(Row-Level Security)  (0) 2025.05.07
Next.js + Supabase로 시작하는 인증 및 DB 연동  (0) 2025.05.07
Supabase 란  (0) 2025.05.06

Supabase를 쓰다 보면 반드시 마주치게 되는 개념 중 하나가 바로 RLS(Row-Level Security)입니다.

이 글에서는 RLS가 무엇이고, 왜 필요한지, Supabase에서는 어떻게 설정하고 활용하는지를 정리했습니다.


RLS란 무엇인가?

RLS(Row-Level Security)는 테이블의 각 행(row)에 대해 접근 권한을 제어하는 보안 기능입니다. PostgreSQL의 고급 기능 중 하나로, Supabase는 이 기능을 적극 활용해 사용자 단위 데이터 보호를 제공합니다.

예를 들어, 사용자가 자신의 할 일 목록만 조회할 수 있게 하려면 어떻게 해야 할까요?

전통적인 백엔드라면 쿼리마다 user_id 조건을 직접 걸어줘야겠지만, RLS를 활용하면 DB 레벨에서 정책(policy)을 설정해서 자동으로 필터링할 수 있습니다.


RLS가 없으면 생기는 문제

// 로그인된 유저가 아니라도 전체 todos를 다 조회할 수 있음
const { data } = await supabase.from('todos').select('*');

이런 코드가 있다면 모든 유저의 데이터가 노출될 수 있습니다.


Supabase에서의 RLS 활용

Supabase는 로그인한 사용자의 ID를 auth.uid()로 제공합니다. 이를 활용해 RLS 정책을 구성할 수 있습니다.

1. RLS 활성화

alter table todos enable row level security;

2. 행 단위 접근 정책(policy) 추가

create policy "Users can view own todos"
on todos for select
using (auth.uid() = user_id);

3. 삽입/수정 권한 제어도 가능

create policy "Users can insert their own todos"
on todos for insert
with check (auth.uid() = user_id);

프론트엔드에서는 어떻게 달라질까?

RLS 정책이 적용되면, 프론트엔드에서 다음처럼 단순한 쿼리를 날려도 안전합니다.

const { data } = await supabase.from('todos').select('*');

이제는 이 쿼리가 자동으로 로그인한 사용자에 해당하는 데이터만 반환합니다.


RLS는 Supabase에만 있는 개념일까?

아닙니다. RLS는 PostgreSQL의 기본 기능입니다. Supabase는 이를 래핑(wrapping)해서 더 쉽게 다룰 수 있도록 콘솔 UI와 API에서 제공할 뿐입니다.

구분 설명
Supabase PostgreSQL 기반, auth.uid() 제공, RLS 정책 쉽게 구성 가능
PostgreSQL 원래 RLS 기능이 존재, 직접 SQL로 구성 필요

Supabase에서 RLS를 강조하는 이유

Supabase는 PostgreSQL 기반이기 때문에, PostgreSQL의 RLS 기능을 그대로 활용할 수 있습니다. 특히 BaaS 백엔드에서 클라이언트가 직접 쿼리를 날리는 구조이다 보니, RLS 없이 보안사고가 발생할 가능성이 높습니다. 그래서 RLS가 보안 핵심 기능으로 강조되는 것입니다.

 

요약

  • RLS는 사용자마다 다른 행(row)에 접근하도록 제한하는 데이터 보안 기능입니다.
  • Supabase에서는 auth.uid()를 통해 로그인 사용자의 ID를 받아 정책을 구성할 수 있습니다.
  • 프론트엔드에서는 단순한 쿼리만 작성해도 자동으로 보안이 적용되어 편리하고 안전합니다.

'Back-End > Supabase' 카테고리의 다른 글

Supabase 오류 - "Invalid URL" 해결 방법  (0) 2025.05.07
Next.js + Supabase로 시작하는 인증 및 DB 연동  (0) 2025.05.07
Supabase 란  (0) 2025.05.06

Next.js에서 Supabase를 활용해 인증 및 데이터베이스 연동을 시작하는 방법을 단계별로 정리한 글입니다.

Supabase는 Firebase의 오픈소스 대안으로, Postgres 기반의 데이터베이스와 인증, 스토리지 기능을 제공합니다.


프로젝트 준비

1. Supabase 프로젝트 생성

  1. https://supabase.com에 가입 및 로그인
  2. New Project 클릭 후 프로젝트 생성 (비밀번호는 꼭 기억)
  3. 생성 후 Settings > API에서 다음 정보 확인:
    • Project URL
    • anon/public API key

2. Next.js 프로젝트 설정

npx create-next-app@latest next-supabase-demo
cd next-supabase-demo
npm install @supabase/supabase-js

3. Supabase 클라이언트 설정

lib/supabaseClient.ts 파일 생성:

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!

export const supabase = createClient(supabaseUrl, supabaseAnonKey)

.env.local 파일:

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

소셜 로그인, 직접 구축할까?

Supabase는 Google, GitHub, Facebook 등의 OAuth 기반 소셜 로그인을 기본 제공하지만, 실무에서는 사용자 정보와 인증 흐름을 직접 제어할 수 있는 커스터마이징이 더 바람직할 수 있습니다.

소셜 로그인 Provider 설정 예시

왜 직접 구현하는 게 좋을까?

  • 토큰 저장 및 갱신을 우리 서비스에서 직접 제어 가능
  • 사용자 정보를 우리 DB 테이블에 명확히 저장 가능
  • 고급 기능 (예: 친구 목록, 캘린더 접근 등) 연동 가능
  • 향후 SSO, 2FA 등의 확장에도 유리함

커스텀 OAuth 흐름 요약

[프론트] 로그인 버튼 클릭
  → /api/auth/kakao 등으로 리다이렉트
    → Kakao/Google에서 로그인
      → access_token 반환
        → 백엔드에서 사용자 정보 저장 + 세션 발급

예제 코드: Kakao OAuth (API Route)

// pages/api/auth/kakao/callback.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import axios from 'axios'
import { supabase } from '@/lib/supabaseClient'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const code = req.query.code as string

  const { data: tokenRes } = await axios.post(
    'https://kauth.kakao.com/oauth/token',
    new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: process.env.KAKAO_CLIENT_ID!,
      redirect_uri: process.env.KAKAO_REDIRECT_URI!,
      code,
      client_secret: process.env.KAKAO_CLIENT_SECRET!,
    }),
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  )

  const kakaoAccessToken = tokenRes.access_token

  const { data: userRes } = await axios.get('https://kapi.kakao.com/v2/user/me', {
    headers: { Authorization: `Bearer ${kakaoAccessToken}` },
  })

  const kakaoUser = userRes

  await supabase.from('users').upsert({
    id: kakaoUser.id,
    email: kakaoUser.kakao_account.email,
    nickname: kakaoUser.properties.nickname,
    provider: 'kakao',
  })

  res.redirect('/')
}

테이블 생성 및 연동

예시: todos 테이블 생성

테이블 생성 및 필드 구성 예시

  • 필드: id, title, is_done, user_id
  • RLS (Row-Level Security) 설정 후 다음 정책 추가:
create policy "Users can view own todos"
on todos for select
using (auth.uid() = user_id);

프론트엔드 연동 예시:

const { data, error } = await supabase
  .from('todos')
  .select('*')
  .eq('user_id', user.id)

await supabase.from('todos').insert([
  { title: '블로그 쓰기', is_done: false, user_id: user.id }
])

테이블 생성 및 연동

아래는 Supabase SQL Editor나 초기 설정 시 사용할 수 있는 회원 및 할 일 테이블 생성 쿼리 예시입니다.

회원 테이블: users

create table if not exists users (
  id bigint primary key,
  email text unique not null,
  nickname text,
  provider text,
  created_at timestamp with time zone default timezone('utc'::text, now())
);

할 일 테이블: todos

create table if not exists todos (
  id bigint generated always as identity primary key,
  title text not null,
  is_done boolean default false,
  user_id bigint references users(id),
  created_at timestamp with time zone default timezone('utc'::text, now())
);

RLS 정책 (todos)

alter table todos enable row level security;

create policy "Users can view own todos"
on todos for select
using (auth.uid()::bigint = user_id);

create policy "Users can insert their own todos"
on todos for insert
with check (auth.uid()::bigint = user_id);​
 

마무리 및 다음 단계

  • Supabase는 인증, DB, 스토리지, 실시간 기능까지 제공하는 매우 강력한 BaaS입니다.
  • 커스터마이징된 소셜 로그인은 더 나은 통제력과 확장성을 제공합니다.
  • Next.js와의 궁합도 좋아 SSR, SSG에서도 유연하게 사용할 수 있습니다.

'Back-End > Supabase' 카테고리의 다른 글

Supabase 오류 - "Invalid URL" 해결 방법  (0) 2025.05.07
Supabase에서의 RLS(Row-Level Security)  (0) 2025.05.07
Supabase 란  (0) 2025.05.06

Supabase는 [오픈소스 백엔드 서비스(BaaS, Backend-as-a-Service)]입니다. 보호, 인증, 데이터베이스, 스토리지 기능을 포함한 백엔드를 평시 소속자도 간단히 구성할 수 있게 해주는 포스컴 기능입니다.

"Supabase is an open-source Firebase alternative."

즉, Firebase와 유사한 개발 환경을 제공하면서도 더 유연하고 다양한 기능 구성이 가능합니다.


Supabase 구성 요소

기능구현 기술설명

기능 구현 기술 설명
Database PostgreSQL 강력하고 확장성 높은 RDBMS
API PostgREST 데이터베이스를 REST API로 자동 노출
실시간 기능 Realtime Server (via WebSocket) 데이터 변경사항을 실시간 감지
인증/보안 GoTrue JWT 기반 사용자 인증
스토리지 S3 compatible storage 이미지, 파일 관리
대시보드 Supabase Studio 구글 UI 관리 콘솔

Supabase의 장점

  1. PostgreSQL 기반
    유니코리어와 SQL에 익숙한 개발자들에게 차이점이 없음.
  2. 오픈소스
    베너 종속성 없이 자유로 환경 구성가능.
  3. 빠른 구성 속도
    인증, API, DB 파이프와 같은 기능이 몇분 내 구성.
  4. Self-hosting 가능
    Docker로 구성해 복잡한 개발 환경에 대비할 수 있음.
  5. Firebase와 비슷하지만 SQL 기반
    Firebase의 NoSQL이 불편했다면 Supabase는 더 단순한 구조.

Supabase vs Firebase 비교

항목 Supabase Firebase
데이터베이스 PostgreSQL (SQL 기반) Firestore (NoSQL 기반)
실시간 기능 WebSocket 기반 Realtime Firestore 내장 실시간 처리
인증 시스템 GoTrue (JWT 기반) Firebase Auth (OAuth, SSO 등 지원)
오픈소스 여부 오픈소스 폐쇄적 (Google 독점)
호스팅 가능 여부 Self-host 가능 Google 인프라에 종속
백업/복원 PostgreSQL 기반으로 자유로움 제한적 UI 기반 백업만 가능
사용 용이성 초보자도 쉽게 접근 가능 모바일 SDK에 특화, 사용 용이함

총평:

  • Firebase는 모바일 앱과 Google 생태계 통합이 강점.
  • Supabase는 SQL 기반 + 오픈소스 + 자율적 관리가 필요한 프로젝트에 적합.

언제 사용하면 좋을까?

  • MVP 디렉토리 복잡하게 건설하고 싶을 때
  • 인증, DB, 실시간성과 같은 기능을 해결할 인력이 부족할 때
  • Firebase가 NoSQL이었다는 것에 통지한 경우
  • 오픈소스 보안과 자율리가 중요한 개발 건설 경우

활용 예시

  • Todo 앱: Supabase 인증 + PostgreSQL DB로 개인 타입 개체 관리
  • 블로그: Markdown + 취소적 댓글 + 실시간 행정
  • 모바일 청첩장: React + Supabase 로 방명록 기능 구성

더 알아보기


마무리

Supabase는 복잡한 건설을 간단히 구성하고자 하는 개발자에게 도움이 되는 현대적인 BaaS 해결책입니다. Firebase에 대한 여부가 당신의 고민이었다면, Supabase는 대안이 되어 줄 수 있을 것입니다.

+ Recent posts