회사 계정으로만 들어오는 사이트 만들기 — 구글 로그인 붙이기 (파이어베이스)
이 페이지 목차
시작 전에1단계 · 회사 메일만 쓰는 로그인 페이지 만들기2단계 · 파이어베이스 콘솔에서 준비하기 (내가 직접)3단계 · 설정값을 페이지에 넣기4단계 · 「이 검사로 정말 막히나?」 물어보기5단계 · 공지를 로그인 뒤에서만 보이게 하기6단계 · 규칙을 점검하고 콘솔에 올리기7단계 · 올려서 두 계정으로 시험하기다 됐습니다 — 이제 이렇게 말하면 됩니다막히면한 번에 맡기기 (익숙해진 다음에)내가 만들 때는「로그인 단추를 달았다」와 「남이 못 들어온다」는 다릅니다. 인터넷에 올린 웹페이지 파일(HTML·그림)은 로그인과 상관없이 주소만 알면 누구나 내려받습니다. 그래서 이 편은 둘을 나눕니다. 화면의 로그인 검사는 안내이고, 진짜로 막는 문은 자료(데이터) 앞에 거는 규칙입니다. 1단계에서 로그인 화면을 만들고, 4~6단계에서 진짜 문을 만듭니다. (예시 메일은 가짜 이름 @ganada.example 입니다. 따라 할 때는 내 회사 메일 뒷부분으로 바꿔 치세요.)
1·3·4·5·6단계의 🤖 은 제가 클로드로 실제로 돌려 받은 답입니다. 2단계와 7단계는 파이어베이스 콘솔·인터넷에 올리는 일이라 내가 직접 하고(공식 문서로 맞춘 안내), 7단계의 두 답(올리기)만 **「예시 답」**입니다.
시작 전에
- 빈 폴더 하나를 만들고(영문 이름, 예:
ganada-login), 그 폴더에서 클로드(Claude Code)를 엽니다. 여는 법과 승인 방식(처음에는 Manual)은 02편 시작 전에와 같습니다. - 구글 계정으로 파이어베이스 콘솔(console.firebase.google.com)에 들어갈 수 있어야 합니다. 이 편의 파이어베이스 프로젝트는 무료(Spark) 요금제 그대로 씁니다. 구글 로그인이 무료인지는 요금표가 방식별로 적지 않아 확인하지 못했습니다. 요금표에서 확인한 것은 전화번호 로그인은 문자 한 통마다 돈이 드는 쪽(유료 Blaze) 이라는 것과, Firestore 무료는 하루 읽기 5만 건까지라는 것입니다. 이 편은 전화번호 로그인을 쓰지 않습니다. (요금표)
- 올릴 곳은 09편의 클라우드플레어 워커스를 가정합니다. 다른 정적 파일 호스팅도 됩니다. 이 편의 로그인 페이지는 서버 없이 파일만 올립니다.
- 시험하려면 구글 계정이 둘 필요합니다. 회사 계정 하나, 회사가 아닌 계정(개인 구글 계정 등) 하나.
준비물 자세히 (용어)
- **파이어베이스(Firebase)**는 구글이 주는 앱 만들기 도구 모음입니다. 이 편은 그중 두 가지를 씁니다. Authentication(로그인을 대신 해 주는 서비스)과 Firestore(구글 클라우드의 문서형 데이터 저장소).
- 구글 로그인은 비밀번호를 우리가 받지 않고 구글에게 「이 사람이 맞다」는 확인서(토큰)를 받는 방식입니다. 우리는 비밀번호를 보관하지 않습니다.
- **보안 규칙(Security Rules)**은 Firestore 가 읽기·쓰기 요청을 받을 때마다 구글 서버에서 허락 여부를 가리는 규칙입니다. 브라우저에서 고칠 수 없습니다. 파일 이름은
firestore.rules입니다. - **
firebaseConfig(설정값)**는 「이 페이지가 어느 파이어베이스 프로젝트를 쓰는지」 알려 주는 값 몇 개(프로젝트 이름 같은 것)입니다. 비밀번호가 아닙니다. 공식 문서는 파이어베이스 서비스용으로 제한된 키는 비밀로 다룰 필요가 없다고 하고, 데이터는 보안 규칙이 지킨다고 적고 있습니다. (API 키 안내) - **
hd**는 구글 로그인 때 「이 회사 계정을 먼저 보여 줘」라고 계정 고르는 화면에 알려 주는 힌트입니다. 구글 문서가 직접 「접근을 막는 데 쓰지 말라」고 적고 있습니다. (구글 안내) - 로그인을 마치면 구글이 돌려주는 확인서(ID 토큰)에도
hd값이 들어 있고, 구글은 회사 사람만 들이려면 이 값을 확인하라고 합니다. 다만 파이어베이스 규칙에서는 이 값을 볼 수 없어서(「막히면」의 「회사 메일 주소 모양의 개인 구글 계정」), 이 편의 진짜 문은 메일 인증 + 메일 끝 + 규칙입니다. 회사가 구글 워크스페이스(회사용 구글 계정)를 쓰지 않으면hd는 아예 없지만, 이 편의 방식은 그래도 동작합니다.
1단계 · 회사 메일만 쓰는 로그인 페이지 만들기
로그인 화면을 public 폴더에 만듭니다(로그인 뒤 화면은 5단계에서). 아직 파이어베이스를 만들지 않았으니 설정값 자리는 비어 있어도 됩니다.
✅ 이렇게 나오면 성공 — 폴더에 public/index.html(로그인 화면)과 public/app.js(로그인 코드), public/firebase-config.js(설정값 자리), 그리고 public 밖에 firestore.rules 가 생기면 다음 단계로. 파일 이름과 개수는 클로드마다 조금 달라도 괜찮습니다. 클로드가 파이어베이스 Hosting 으로 올리는 명령(firebase deploy)을 안내해도 따라 하지 마세요. 이 편은 올릴 곳을 09편의 클라우드플레어로 둡니다. 답에서 「보안 장치가 아닙니다」·「실제로 막는 곳은 규칙」이라는 말을 기억해 두세요. 4단계의 주제입니다.
2단계 · 파이어베이스 콘솔에서 준비하기 (내가 직접)
이 단계는 클로드에게 말하지 않고 내가 직접 합니다. 화면 이름은 공식 문서에서 확인한 것이고, 한국어 화면이면 이름이 조금 다를 수 있습니다.
- 콘솔에서 새 프로젝트를 만드는 단추를 누르고, 프로젝트 이름을 적습니다(예:
ganada-login). 프로젝트 ID 는 이름에서 자동으로 만들어지며 만든 뒤에는 바꿀 수 없습니다. 약관이 나오면 읽고 계속하고, 분석(Google Analytics)·Gemini 설정은 이 편에서 필요 없습니다. 「프로젝트 만들기(Create project)」를 누릅니다. - 프로젝트 첫 화면에서 웹 아이콘(
</>모양)을 눌러 앱을 등록합니다. 앱 닉네임(콘솔에서만 보이는 이름)을 적고 「앱 등록(Register app)」을 누르면 설정값(firebaseConfig)이 나옵니다. 복사해 둡니다. 안내 화면에서 SDK 를 설치하라는 부분은 따라 하지 않아도 됩니다(1단계 페이지가 구글 주소에서 바로 불러옵니다). - 왼쪽 메뉴에서 Security → Authentication 으로 들어가 시작하고, 로그인 방법(Sign-in method) 탭에서 Google 을 사용 설정한 뒤 저장합니다. 지원 이메일을 고르라고 하면 내 이메일을 고릅니다.
- 이 편의 7단계에서 승인된 도메인도 더합니다(주소가 정해진 뒤). 그 자리는 Authentication → 설정(Settings) 탭의 「승인된 도메인(Authorized domains)」 입니다.
✅ 이렇게 나오면 성공 — 설정값(4~6줄짜리 글)을 복사해 두었고, 로그인 방법 목록에서 Google 이 「사용 설정됨」으로 보이면 됩니다.
3단계 · 설정값을 페이지에 넣기
복사한 설정값을 클로드에게 붙여 넣어 firebase-config.js 에 넣게 합니다.
✅ 이렇게 나오면 성공 — 클로드가 설정값을 넣었다고 하면 다음 단계로. 파일을 열어 내 프로젝트 이름이 보이는지 눈으로 봐도 좋습니다.
4단계 · 「이 검사로 정말 막히나?」 물어보기
가장 중요한 단계입니다. 회사 계정이 아니면 못 들어오는지, 진짜로 막는 곳이 어디인지 클로드에게 직접 묻습니다.
✅ 이렇게 나오면 성공 — 클로드가 「페이지 검사로는 막지 못한다, 규칙이 실제로 막는다」고 답하면 됩니다. 답이 길게 나오면 앞부분만 읽어도 됩니다. (답의 나머지에는 퇴사자 처리나 서버를 두는 방법 같은 다른 이야기도 나왔습니다. 이 편은 쓰지 않습니다.)
5단계 · 공지를 로그인 뒤에서만 보이게 하기
로그인한 사람에게만 보여 줄 공지 한 줄을 HTML 이 아니라 Firestore 에 두고, 로그인한 뒤 읽어 오게 합니다.
✅ 이렇게 나오면 성공 — app.html 안에 공지 글자가 없고(공지를 읽어 오는 코드만 있고), 클로드가 공지 문서의 위치(컬렉션·문서·필드 이름)를 알려 주면 다음 단계로. 이름은 site·config 등으로 달라도 괜찮습니다. 이 답에서 클로드가 규칙도 같이 좁혔다고 알려 주기도 합니다. 일부러 규칙이 넓은 채로 두고 「이렇게 할까요?」라고 되묻는 때도 있습니다(처음 시험에서는 그랬습니다). 그러면 「응」이라고 하세요.
6단계 · 규칙을 점검하고 콘솔에 올리기
규칙이 정말 「공지 하나 읽기만」으로 좁혀졌는지 확인하게 합니다. 그다음 콘솔에서 내가 직접 규칙을 올립니다.
이렇게 클로드가 「이미 되어 있다」고 알려 주기도 합니다. 허용 줄이 하나뿐이다라는 마지막 정리를 확인하는 단계입니다.
firestore.rules 를 열어 회사 계정을 가리는 줄도 눈으로 봅니다. 제 시험에서 클로드가 만든 줄은 이랬습니다.
request.auth != null
&& request.auth.token.email_verified == true
&& request.auth.token.email.lower().matches('.*@ganada[.]example$')
request.auth != null은 「로그인했다」,email_verified == true는 「메일 주소의 주인임을 구글이 확인했다」입니다.lower()는 대문자를 소문자로 바꾸고,matches(...)는 메일 주소 전체가 「아무 글자 +@ganada.example」 꼴일 때만 참입니다. 두 기능 모두 규칙 언어 설명서의 문자열(String) 항목에 있습니다. (규칙 언어 String)endsWith(...)로 적혀 있으면 고치게 하세요. 규칙 언어의 문자열 기능 목록에는endsWith가 없습니다(공식 안내 한 곳의 예시에 이 꼴이 있지만 설명서와 다릅니다). 이렇게 말하세요: "회사 메일 검사를 request.auth.token.email.lower().matches 꼴로 바꿔 줘."
이제 콘솔에서 내가 직접 세 가지를 합니다.
- Firestore 데이터베이스 만들기 — 시작 모드를 고르라고 하면 프로덕션 모드(기본으로 막아 두는 쪽)를 고릅니다. 공식 시작 안내는 테스트 모드를 「누구나 읽고 덮어쓸 수 있다」, 프로덕션 모드를 「웹·모바일에서의 읽기·쓰기를 모두 막는다」고 설명하고, 보안 점검표는 새 데이터베이스를 기본값(프로덕션 모드)으로 두라고 안내합니다. 테스트 모드는 고르지 마세요. (시작 안내 · 보안 점검표)
- 공지 만들기 — 데이터 탭에서 컬렉션
site→ 문서notice→ 문자열 필드text에 공지 한 줄(예: 「이번 주 금요일은 전체 청소의 날입니다」)을 적습니다. 경로는 5단계 답과 글자 그대로 맞추세요(클로드가 다른 이름을 정했다면 그 이름으로). 콘솔은 규칙의 영향을 받지 않으므로 공지를 바꿀 때도 여기서 고칩니다. - 규칙 올리기 — 콘솔에서 Firestore 의 규칙(Rules) 탭을 열어
firestore.rules파일의 내용을 붙여 넣고 게시(Publish) 를 누릅니다. (공식 안내) 게시한 뒤 규칙 화면에 붙여 넣은 내용이 그대로 있는지 눈으로 확인하세요. 콘솔에는 규칙을 **시험해 보는 도구(Rules Playground)**도 있습니다. 다만 공식 설명에는 이메일을 넣는 칸이 보이지 않아, 이 편은 7단계처럼 실제 로그인으로 시험합니다.
✅ 이렇게 나오면 성공 — 규칙 화면에 match /site/notice(내 경로 이름) 가 보이고 게시가 끝났다고 나오면 다음 단계로.
7단계 · 올려서 두 계정으로 시험하기
09편 방법으로 public 폴더를 올립니다. 이 폴더에는 올리는 설정 파일(wrangler.jsonc)이 아직 없으니 클로드가 먼저 만들게 합니다(09편 3단계).
점검 결과를 읽고 괜찮으면 올리게 합니다. 클라우드플레어에 아직 로그인하지 않았다면 09편 5단계처럼 브라우저 로그인은 내가 직접 합니다.
올린 주소가 생기면 내가 직접 콘솔의 Authentication → 설정 → 승인된 도메인 → 도메인 추가(Add domain) 에 그 주소(이름.내계정이름.workers.dev)를 더합니다. 이 목록에 없는 주소에서는 구글 로그인이 거절됩니다. 그다음 세 가지를 시험합니다.
| 시험 | 이렇게 하면 | 이렇게 보이면 성공 |
|---|---|---|
| ① 회사 계정 | 올린 주소를 열고 로그인 → 회사 구글 계정 고르기 | 내 이메일과 공지 한 줄이 보입니다 |
| ② 회사가 아닌 계정 | 로그아웃하고 개인 구글 계정(회사 메일이 아닌 것)으로 로그인 | 「@ganada.example 계정만 사용할 수 있습니다」(내 회사 메일 뒷부분) 안내가 나오고 공지는 안 보입니다 |
③ 로그인 없이 app.html | 새 시크릿 창에서 올린주소/app.html 을 직접 열기 | 로그인 페이지로 돌려보내지고 공지 글은 어디에도 없습니다 |
✅ 이렇게 나오면 성공 — 세 시험이 표대로 나오면 끝입니다. ③에서 파일 자체는 누구나 받을 수 있지만, 그 안에 공지가 없고 규칙이 공지 읽기를 막으니 회사 사람만 공지를 봅니다. 이것이 「안내」와 「진짜 문」의 차이입니다.
다 됐습니다 — 이제 이렇게 말하면 됩니다
항상 이 폴더에서 클로드를 열고 이야기합니다.
- 「지금 규칙이 누구에게 무엇을 허락하는지 쉬운 말로 설명해 줘.」
- 「새 컬렉션 teamlinks 를 회사 계정만 읽게 규칙에 더해 줘. 쓰기는 막아 줘.」
- 「공지를 두 줄까지 보여 주도록 app.html 을 고쳐 줘. 공지 글은 HTML 에 넣지 마.」
- 「규칙을 바꿨으니 회사 계정이 아닌 경우에 막히는지 시험하는 방법을 알려 줘.」
규칙을 바꿀 때마다 콘솔에 다시 올려야 효과가 있습니다.
막히면
- 구글 로그인 창이 안 뜨거나 「승인되지 않은 도메인」 오류가 난다 → 올린 주소가 승인된 도메인 목록에 없는 경우가 가장 흔합니다. 공식 문서도 같은 오류(
auth/unauthorized-domain)를 이 원인으로 설명합니다. 주소 전체를 7단계처럼 더하세요. 이렇게 다시 말하세요: "로그인할 때 나는 오류 코드를 화면에 보여 주게 고쳐 줘." (1단계 페이지는 오류 코드를 화면에 보여 줍니다.) - 내 PC 에서 파일을 더블클릭해 열면 로그인이 안 된다 → 이 페이지는 브라우저 모듈을 불러오는 방식이라 파일로 직접 열면 안 되는 경우가 많습니다(클로드도 시험 답에서 같은 말을 했습니다). 올린 주소에서 시험하세요. 컴퓨터 안에서 시험하려면 주소가
localhost인 간단한 서버가 필요하고, 그 주소도 승인된 도메인에 넣어야 합니다. 2025년 4월 28일 이후 만든 파이어베이스 프로젝트는localhost가 처음부터 들어 있지 않다고 공식 문서가 적고, 운영 프로젝트에서는 빼 두라고 권합니다. - 로그인은 되는데 공지가 「권한이 없습니다」로 나온다 → ① 규칙을 아직 게시하지 않았거나 ② 콘솔에 만든 경로와 규칙의 경로가 한 글자라도 다르거나 ③ 로그인한 메일이 인증되지 않은 경우입니다. 게시 직후에는 반영에 잠깐 걸릴 수 있습니다. 이렇게 다시 말하세요: "app.html 이 읽는 경로와 firestore.rules 의 경로가 똑같은지 비교해서 알려 줘."
- 폰에서 로그인 화면이 깜빡이거나 계속 실패한다 → 제가 겪은 일입니다(아래). 공식 문서는 화면을 옮겨 갔다 오는 방식(리디렉션)이 제3자 저장소를 막는 브라우저에서 깨진다고 적고, 대안으로 팝업 방식을 듭니다. 팝업은 가끔 기기에서 막히고 폰에서는 덜 매끄럽다고도 적혀 있습니다. 이 편의 코드는 팝업 방식입니다. 팝업이 막히면 이렇게 말하세요: "폰에서 로그인이 실패하는데, 로그인 방식(팝업·리디렉션) 중 무엇을 쓰고 있는지 알려 주고 공식 문서에 맞는 쪽으로 고치는 방법을 먼저 설명해 줘."
- 파이어베이스 사용자 목록(Authentication)에 회사 밖 계정이 보인다 → 이 편의 방식에서는 정상일 수 있습니다. 회사 밖 계정이 로그인을 시도하면 파이어베이스가 계정을 만들고, 이 편의 시험 코드는 그 계정을 바로 로그아웃시킬 뿐 지우지는 않습니다(코드에 따라 지우려 시도하는 판도 있습니다). 규칙이 그 계정에게 데이터를 주지 않으니 자료는 안전합니다. 계정이 만들어지는 것 자체를 막으려면 서버 쪽 코드(blocking function)가 필요한데, 공식 문서는 이 기능을 쓰려면 Authentication 을 Identity Platform 으로 올리라고 합니다. 이 편의 범위를 벗어납니다. (안내)
- 회사 메일 주소 모양의 개인 구글 계정도 통과하지 않을까? → 통과할 수 있습니다. 이메일 끝만으로는 부족할 수 있습니다. 구글 계정은 Gmail 이 아닌 원래 쓰던 메일 주소로도 만들 수 있고, 그 주소로 온 코드를 넣으면 「인증됨」이 됩니다(구글 계정 도움말). 예를 들어 회사가 구글 워크스페이스를 쓰지 않는다면, 재직 중에 회사 메일로 개인 구글 계정을 만든 사람은 퇴사한 뒤에도 그 계정으로 이 편의 규칙(메일 인증 + 메일 끝)을 통과할 수 있습니다. 구글 문서도 「메일 주소의 도메인만으로 워크스페이스 사용자를 가릴 수 없다」며, 구글이 서명한 확인서(ID 토큰)의
hd값을 확인하라고 합니다. 그런데 파이어베이스 규칙이 보는 확인서(request.auth.token)의 공식 항목 목록에는hd가 없습니다(규칙과 인증). 그 값을 보려면 서버 쪽 코드(위 항목의 blocking function — Identity Platform 으로 올려야 씀)가 필요해 이 편의 범위를 벗어납니다. 서버 없이 더 엄격히 하려면 허용할 사람의 명단으로 좁히고, 퇴사하면 명단에서 빼세요. 제 플랫폼은 가입을 신청으로 받고 관리자가 승인한 뒤에야 반영합니다. 이렇게 말해 볼 수 있습니다(이 말은 제가 시험하지 못했습니다): "규칙에 허용할 사람 이메일 명단을 둘 컬렉션을 더하고, 그 명단에 있는 사람만 공지를 읽게 바꿔 줘." - 페이지 파일(HTML) 자체도 회사 사람만 보게 하고 싶다 → 서버 없이 파일만 올리는 이 편의 방식으로는 안 됩니다. 시험에서 클로드는 서버 코드나 사이트 앞에 두는 인증 서비스(Cloudflare Access·Google IAP 를 예로 들었습니다)가 필요하다고 답했고, 이 편은 그 서비스를 확인하지 못했습니다. 제 플랫폼은 사이트 앞에 작은 서버 프로그램(클라우드플레어 워커)을 두어, 자료 요청이 오면 로그인 토큰을 검사한 뒤 본인 몫만 내줍니다. (뒷이야기 13단계 9번)
- 공지를 읽다가 「한도」 오류가 난다 → 읽을 때마다 읽기 1건이 쌓입니다. 무료 요금제는 하루 5만 건까지입니다(요금표). 직원 전체가 새로고침할 때마다 읽으면 빨리 찹니다. 이렇게 말하세요: "공지는 한 번 읽으면 브라우저에 한 시간 저장해서 매번 읽지 않게 고쳐 줘."
- 클로드가 영어로 답한다 → 이 편을 돌릴 때 한 번 영어로 답했습니다. 이렇게 다시 말하세요: "한국어로 답해 줘. 앞으로도 계속 한국어로 답하게 CLAUDE.md 에 한 줄 적어 줘."
- 코드 안의
firebasejs/11.0.2같은 숫자는 무엇인가 → 클로드가 아는 파이어베이스 부품의 버전입니다. 이 숫자가 낡았다고 느껴지면 이렇게 말하세요: "공식 문서에 나온 최신 버전 주소로 바꿔 줘." 공식 문서 예시는 시험일에 13 번대였습니다.
한 번에 맡기기 (익숙해진 다음에)
긴 프롬프트 펼치기 — 위 단계를 한 번에 시키는 말
위 1·3·5·6단계의 파일 만들기를 한 번에 시킵니다. 빈 폴더에서 클로드를 연 뒤 붙여 넣으세요. 콘솔에서 하는 일(2단계, 6단계의 데이터베이스·공지·규칙 올리기, 7단계의 승인된 도메인)은 내가 직접 합니다. 클로드는 그 일을 안내하고 멈춥니다.
역할: 너는 내 PC 에서 일하는 도우미다. 파이어베이스(Firebase) 구글 로그인으로 우리 회사 메일 계정만 들어오는 웹페이지를 만들고, 회사 자료는 로그인 뒤 데이터베이스(Firestore)에서만 불러오게 하고 그 앞에 보안 규칙을 거는 것까지 도와준다. 나는 초보자이니 어려운 말은 풀어서, 한 단계씩 말해 줘.
맥락: 지금 열려 있는 폴더가 작업 폴더다. 페이지는 public 폴더에 서버 코드 없이 정적 파일(HTML·JS)로 만든다. 파이어베이스 SDK 는 공식 gstatic 주소에서 브라우저 모듈로 불러온다(설치 없음). 정적 파일은 로그인과 상관없이 주소를 알면 누구나 받으므로 비밀과 회사 자료는 HTML 에 넣지 않는다. 자료는 Firestore 에 두고 firestore.rules 로 막는다. 브라우저의 도메인 검사와 hd 값은 안내일 뿐 보안이 아니다. 콘솔 화면에서 하는 일(프로젝트 만들기, 로그인 켜기, 데이터베이스 만들기, 규칙 게시, 승인된 도메인 추가)은 사람이 직접 한다.
입력: <운영체제>, <쓰는 클로드: Claude Code 터미널 / 데스크톱 앱의 Code 탭>, <회사 메일 뒷부분: 예 ganada.example>, <공지 문구: 예 이번 주 금요일은 전체 청소의 날입니다>
작업:
① 확인 — 지금 폴더의 전체 경로를 말해 준다. public 폴더나 firestore.rules 가 이미 있으면 덮어쓰지 말고 멈춰서 묻는다.
② 만들기 — 아래 파일을 만든다.
- public/index.html : 구글 로그인 단추(팝업 방식). 로그인하면 이메일이 인증되었고 회사 메일 뒷부분과 정확히 같을 때만 public/app.html 로 보낸다. 아니면 방금 생긴 계정을 지우려 시도하고 로그아웃한 뒤 안내 문구를 보여 준다. hd 값은 힌트로만 넣고 주석으로 그렇게 적는다. 오류가 나면 오류 코드를 화면에 보여 준다.
- public/app.html : 빈 틀. 로그인과 회사 계정 확인이 끝난 뒤에만 Firestore 의 config 컬렉션 notice 문서의 text 필드를 읽어 보여 준다. 문서가 없을 때·권한이 없을 때·그 밖의 오류일 때 각각 다른 문구를 보여 준다. 공지 문구는 이 파일에 적지 않는다.
- public/firebase-config.js : 설정값 자리(YOUR_ 로 시작하는 자리 표시)와 허용할 메일 뒷부분.
- firestore.rules : public 밖에 둔다. 회사 계정은 request.auth.token.email_verified == true 이고 request.auth.token.email.lower().matches(회사 메일 뒷부분으로 끝나는 정규식) 일 때만으로 정한다(규칙 언어에는 endsWith 가 없다). config/notice 문서의 get 만 허락하고, 쓰기와 다른 모든 경로는 허락하지 않는다.
③ 사람이 할 일 안내 — 만든 뒤 멈추고 아래를 하나씩 순서대로 안내한다. 콘솔에서 프로젝트 만들기 → 웹 앱 등록하고 설정값 복사 → Authentication 에서 Google 사용 설정 → Firestore 데이터베이스를 프로덕션 모드로 만들기(테스트 모드 금지) → config 컬렉션·notice 문서·text 필드 만들기 → 규칙 탭에 firestore.rules 내용을 붙여 넣고 게시 → 페이지를 올린 뒤 그 주소를 Authentication 설정의 승인된 도메인에 추가. 내가 설정값을 붙여 넣으면 firebase-config.js 에 넣는다.
④ 검증 — 아래 (가)~(마)를 파일을 다시 열어 하나씩 확인하고 결과를 적는다.
⑤ 시험 안내 — 올린 뒤 세 가지를 안내한다. 회사 계정으로 로그인(이메일과 공지가 보여야 함), 회사 밖 계정으로 로그인(안내 문구가 나오고 공지는 안 보여야 함), 로그인 없이 app.html 직접 열기(로그인 페이지로 돌아가고 공지는 없어야 함).
⑥ 마무리 — 초보자 눈높이로 무엇이 만들어졌고, 화면 검사는 안내이고 규칙이 진짜 문이라는 점을 한 문단으로 설명한다. 규칙을 바꾸면 콘솔에 다시 올려야 한다는 것도 알려 준다.
제약: 비밀키·토큰·비밀번호를 출력하거나 파일에 쓰지 않기. 웹 앱 설정값은 공개되어도 되는 식별자이지만 서비스 계정 키(JSON)나 관리자 비밀은 요구하지도 받지도 쓰지도 않기. 오류를 건너뛰지 않기. 기존 파일을 지우지 않기(덮어쓰지도 않기). 이 폴더 밖의 파일을 읽지도 쓰지도 않기. 테스트 모드(누구나 읽고 쓰는 규칙)를 권하지 않기. 브라우저 검사만으로 보안이 된다고 말하지 않기. 서버 코드(Cloud Functions 등)를 만들지 않기.
출력: 한 일, 만든 파일 목록, 검증 결과((가)~(마) 각각 통과/실패), 내가 콘솔에서 해야 할 일(③ 그대로), 남은 문제와 다음 조치.
검증: 아래를 파일을 다시 열어서 전부 확인하고, 하나라도 실패하면 완료로 보고하지 말 것. 콘솔 일과 올리기는 네가 할 수 없으므로 「남은 일」로 적는다.
(가) public 에 index.html·app.html·firebase-config.js 가 있고 firestore.rules 는 public 밖에 있다.
(나) index.html 에 이메일 인증 확인과 도메인 일치 확인이 있고 hd 는 힌트라는 주석이 있다.
(다) 공지 문구(내가 입력으로 준 글자)가 public 아래 어느 파일에도 없다(글자 검색으로 확인).
(라) firestore.rules 에 email_verified 확인과 matches 로 하는 메일 뒷부분 확인이 있고, 허락하는 allow 줄이 config/notice 의 get 하나뿐이다(if false 로 막는 줄은 있어도 된다).
(마) firebase-config.js 에 서비스 계정 키·비밀번호 같은 비밀이 없다.
내가 만들 때는
처음엔 로그인을 가짜로 만들었습니다. 7월 1일 회사 플랫폼의 첫 판은 브라우저 안의 가짜 계정이었고, 그날 17:20 에 파이어베이스 구글 로그인으로 바꿨습니다. 이 편 1단계처럼 도메인 힌트(hd)를 넣고, 로그인 뒤에 이메일 도메인을 한 번 더 확인해 회사 계정만 통과시켰습니다. 비밀번호는 아예 받지 않습니다. 이틀 뒤 폰에서 문제가 터졌습니다. 2026-07-03 15:50 에 이렇게 말했습니다. 「…구글 계정 여러 번 클릭해야 되고 화면 깜빡이면서 됐거든. 뭔가 로그인 시스템이 불안정한 것 같네.」 다음 날 아침(7월 4일 08:10)에는 이렇게 이어 갔습니다. 「이제 로그인이 컴퓨터로 해도 계속 깜빡이고 구글 아이디를 두 번 눌러야 되는 상황이 됐어. 전체적으로 점검해서 뭐가 문제인지 해결책 찾아내 봐. 모바일 문제, 그리고 데스크톱 문제. 문제가 있으면 로그인 방식을 바꾸더라도 방법을 찾아야 돼.」 아이폰에서 로그인이 「missing initial state」 오류로 계속 실패했고, 두 시간이 안 되는 사이에 로그인 방식을 네 번 바꿨습니다. 원인은 구글 로그인 창을 다녀오는 사이 브라우저가 임시 저장소를 지운 것이었습니다. 위 「막히면」의 폰 항목이 이 일입니다.
더 큰 교훈은 그 뒤에 나왔습니다. 로그인은 되어 있었지만 「로그인한 사람은 다 믿는다」는 규칙이 오래 남아 있었습니다. 9월 26일 하루에 같은 꼴의 구멍이 다섯 번 나왔습니다. 직원이 자기 사용자 문서의 부서·등급을 마음대로 고칠 수 있었고, 경비 자료와 영수증 파일과 AI 공용 설정과 가입도 비슷했습니다. 전부 최고 관리자 계정으로만 시험해서 안 보이던 것이었습니다. 그래서 일반 직원 계정의 눈으로 한 번에 훑었고, 자기 사용자 문서는 두 칸만 고치게, 가입은 신청으로만 받고 관리자가 승인한 뒤 반영하게 규칙을 좁혔습니다. 규칙을 올리기 전에 에뮬레이터(내 PC 에서 흉내 내는 시험대)로 읽고 써 보는 시험을 만들어 0개에서 186개까지 늘렸고, 새 시험은 옛 규칙으로 돌려서 실제로 뚫리는지 확인했습니다. 같은 시험을 옛 규칙으로 돌리면 가입 11개가 뚫렸습니다. 올리는 순서도 중요했습니다. 질의를 좁히는 코드를 먼저 배포하고 규칙은 나중에 올립니다. 거꾸로 하면 직원 화면이 멎습니다. 8월 10일 차량 앱을 잠글 때도 같은 것을 배웠습니다. 화면에 비밀번호 칸을 두는 것은 안내일 뿐 방어가 아니고, 진짜 방어는 서버 쪽 규칙입니다. 그리고 규칙이 막는 것과 못 막는 것을 규칙 파일 머리에 적어 두면 다음 사람이 과신하지 않습니다.
→ 뒷이야기 2단계에서 로그인을 진짜로 바꾼 날을, 13단계에서 규칙 시험대와 일반 직원 눈의 보안 점검을 자세히 보세요.