Firebase Custom Claims 사용법: 관리자 권한 구분하기

2026.01.26·수정 2026.07.20·약 12분

Firebase Custom Claims 관리자 권한 핵심 요약

Custom Claims는 프로필 저장소가 아니라 접근 제어용 토큰 정보입니다. 신뢰할 수 있는 Admin SDK 환경에서만 설정하고, 클라이언트는 새 ID token을 받은 뒤 UI를 조정할 수 있습니다. 실제 허용·거부는 Firestore/Storage Rules 또는 ID token을 검증한 서버에서 다시 강제해야 합니다.

검증 기준: 2026-07-19, Firebase Admin/Auth·Security Rules·Emulator 공식 문서 기준입니다. 실제 firebase-admin 버전과 프로젝트 설정은 lockfile 및 Firebase 콘솔에서 먼저 확인하세요.

1. Custom Claims의 역할과 한계를 먼저 고정합니다

관리자 역할을 Admin SDK에서 부여하고 ID token, Security Rules와 서버 검증으로 전달하는 흐름

권한 부여와 권한 집행은 다른 단계입니다

Admin SDK의 setCustomUserClaims는 사용자 계정에 claim을 기록합니다. 그 사실만으로 관리자 API가 보호되는 것은 아닙니다. 클라이언트가 보낸 ID token을 Admin SDK로 검증하거나, Firebase 제품의 Security Rules에서 request.auth.token을 확인해야 접근이 차단됩니다. 공식 전체 흐름은 Firebase Custom Claims 공식 문서에 있습니다.

프로필·요금제 설명 같은 일반 데이터는 claim에 넣지 않습니다

공식 문서는 Custom Claims를 접근 제어에만 사용하라고 권고합니다. payload는 JSON 직렬화 가능해야 하고 예약된 이름을 쓸 수 없으며, 1,000바이트를 넘을 수 없습니다. 이름·아바타·조직 설명 같은 데이터는 Firestore나 서버 데이터베이스에 저장하고, admin·support처럼 권한 판정에 필요한 작은 값만 claim에 둡니다.

데이터 위치 이유
admin: true Custom Claims Rules·서버 접근 제어에 직접 사용
이름·부서·프로필 Firestore/서버 DB 권한 값이 아니며 자주 변경될 수 있음
서비스 계정 키 비밀 관리자·런타임 자격 증명 클라이언트·저장소·블로그에 절대 포함 금지

2. 기존 claim을 확인하고 신뢰 경계 안에서 부여합니다

setCustomUserClaims는 기존 객체 전체를 덮어씁니다

공식 문서상 이 메서드는 기존 custom claims를 항상 덮어씁니다. 이미 supporttenantId가 있다면 { admin: true }만 넘기는 순간 사라질 수 있습니다. 아래 예제는 현재 값을 읽어 병합하지만, 여러 관리 작업이 동시에 실행될 수 있는 환경이라면 중앙 권한 서비스나 직렬화된 작업 큐로 갱신 경쟁까지 막아야 합니다.

// scripts/grant-admin.mjs — 신뢰할 수 있는 서버/로컬 관리자 환경에서만 실행
import { applicationDefault, initializeApp } from 'firebase-admin/app';
import { getAuth } from 'firebase-admin/auth';

initializeApp({ credential: applicationDefault() });

const uid = process.env.ADMIN_UID;
if (!uid) throw new Error('ADMIN_UID is required');

const auth = getAuth();
const user = await auth.getUser(uid);
const nextClaims = { ...(user.customClaims ?? {}), admin: true };

await auth.setCustomUserClaims(uid, nextClaims);
console.log(`admin claim updated for ${uid}`);

서비스 계정 JSON을 코드 옆에 두고 require()하는 방식보다, 실행 환경의 Application Default Credentials나 비밀 관리자를 사용하세요. 로컬 키 파일이 필요한 경우에도 저장소 밖에 두고 .gitignore와 유출 검사에 포함합니다. UID는 요청 본문을 그대로 믿지 말고 사전에 승인된 운영 절차로 결정합니다.

회수도 부여와 같은 수준으로 설계합니다

권한 회수 시에는 현재 claims에서 admin 키를 제거한 새 객체를 저장합니다. claim 변경은 다음 ID token이 발급될 때 반영되며 이미 발급된 token을 그 자체로 즉시 무효화하지 않습니다. 긴급 회수라면 revokeRefreshTokens(uid)로 기존 session의 새 token 발급을 막고, 보호 API가 verifyIdToken(idToken, true) 또는 동일한 취소 검사를 사용하도록 해야 합니다. Firebase 문서상 기존 ID token은 기본 검증만 사용하면 자연 만료까지 최대 약 1시간 활성일 수 있으므로 Firebase 사용자 세션 취소 문서의 비용·오류 처리까지 확인합니다.

3. 토큰 전파 시점과 클라이언트 표시를 구분합니다

새 claim은 사용자가 다시 로그인·재인증하거나, 기존 ID token이 갱신되거나, getIdToken(true)로 강제 갱신했을 때 새 토큰에 반영됩니다. 단순히 “로그아웃해야만 한다”고 한정할 필요는 없습니다. 다만 강제 갱신은 최신 claim을 받는 클라이언트 전파 수단이지 기존 token의 서버 측 취소 검사를 대신하지 않습니다. refresh token까지 취소됐다면 사용자는 다시 인증해야 합니다. 공식 전파 조건은 Firebase Custom Claims 공식 문서, 취소 동작은 Firebase 사용자 세션 취소 문서에서 확인할 수 있습니다.

// UI 노출용 확인일 뿐, 이 값만으로 서버 권한을 허용하면 안 됩니다.
const tokenResult = await auth.currentUser?.getIdTokenResult(true);
const isAdmin = tokenResult?.claims.admin === true;

이 값으로 관리자 메뉴를 숨기고 보이는 것은 사용자 경험을 위한 처리입니다. 공격자는 클라이언트 코드를 수정할 수 있으므로 isAdmin이 true라는 브라우저 상태만으로 데이터 쓰기나 환불 API를 허용하면 안 됩니다.

4. Security Rules와 서버에서 실제 권한을 강제합니다

Firebase Custom Claims를 Firestore Rules와 백엔드 ID token 검증에서 강제하는 구조

Firestore 규칙 예제

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /admin/{document=**} {
      allow read, write: if request.auth != null
        && request.auth.token.admin == true;
    }
  }
}

규칙에서는 인증 여부를 먼저 확인하고 정확한 boolean 비교를 사용합니다. 전체 규칙 문맥과 제품별 문법은 Firebase Security Rules와 Authentication를 기준으로 작성하세요. 운영 컬렉션을 넓은 wildcard 하나로 열기보다 읽기·쓰기·대상 경로를 최소 권한으로 분리합니다.

자체 API·Next.js 서버 예제

import { getAuth } from 'firebase-admin/auth';

export async function requireAdmin(idToken) {
  // true: 서명·만료뿐 아니라 사용자 비활성화와 session 취소까지 확인
  const decoded = await getAuth().verifyIdToken(idToken, true);
  if (decoded.admin !== true) {
    throw new Error('forbidden');
  }
  return decoded.uid;
}

서버는 클라이언트가 별도 JSON으로 보낸 { admin: true }를 신뢰하지 않고 서명된 ID token을 검증해야 합니다. verifyIdToken(idToken, true)는 기본 서명·만료 검증에 사용자 비활성화와 취소된 session 확인을 추가하며 Firebase Auth backend로의 추가 요청 비용이 있습니다. auth/id-token-revoked 또는 auth/user-disabled는 재인증이 필요한 401 계열 응답으로 매핑하고 내부 오류 세부정보를 그대로 노출하지 마세요. 토큰 전달 방식은 Firebase ID token 검증 문서, 취소 검사는 Firebase 사용자 세션 취소 문서를 따릅니다.

5. Emulator와 부정 테스트를 먼저 통과시킵니다

Authentication Emulator는 로컬 Auth 흐름을 실제 프로젝트와 분리해 검증할 수 있습니다. 연결 방법은 Authentication Emulator 연결 문서를 따르고, Firestore/Storage Emulator와 함께 아래 부정 테스트를 자동화하세요.

6. 명시적 결론과 다음 행동

결론: Custom Claims는 관리자 UI 표시 기능이 아니라 Rules와 서버 검증에 전달되는 작은 접근 제어 신호입니다. 부여 스크립트보다 더 중요한 것은 기존 claim 보존, 토큰 갱신, 서버 집행, 회수와 부정 테스트입니다. 다음 행동은 Emulator에서 일반 사용자·관리자·회수된 관리자 3개 시나리오를 먼저 통과시킨 뒤 운영 UID에 적용하는 것입니다.

공식 근거

내부 학습 경로

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

“Firebase Custom Claims 사용법: 관리자 권한 구분하기”에 대한 1개의 생각

댓글 남기기