웹 Google 시트 액세스
Google 시트 액세스는 가져오는 자격 증명을 따른다. 배포된 웹사이트에는 두 가지 진입 경로가 나란히 있다: Google로 로그인(OAuth)하거나, 사용자 자신의 브라우저가 직접 사용하는 서비스 계정 키 파일을 선택한다. Unity / 로컬 경로는 기기 로컬 서비스 계정 키를 그대로 유지한다.
배포된 사이트에서 — OAuth, 읽기와 쓰기
배포된 사이트에서는 로그인한 사용자가 자신의 OAuth 토큰으로 Google 시트를 읽고 쓸 수 있다.
- 최소 권한. 로그인은 기본 프로필과 파일 단위 스프레드시트 접근 권한(
drive.file)만 요청한다. 앱은 사용자가 명시적으로 열어 준 스프레드시트 파일만 읽고 쓸 수 있다. 계정 전체에 걸친 권한은 전혀 없다 — 나머지 Drive를 나열하거나 둘러볼 수 없으며, 열어 주지 않은 파일은 보이지 않는 채로 남는다. - 동일한 코어 플랜. 웹에서의 쓰기는 다른 모든 경로와 정확히 동일한 코어 플랜과 동일한 공유 낙관적 잠금 검증을 거쳐 실행된다 — 라이브 시트는 전송 직전에 다시 점검되므로, 임포트 이후 제삼자가 변경한 셀은 건너뛸 뿐 결코 덮어쓰지 않는다. 전송 계층만 다를 뿐이다 — 이 경로에서는 OAuth 베어러 토큰을 싣는다.
- 시트의 ACL이 최종 권한이다. SheetForge는 누가 쓸 수 있는지를 결정하지 않는다. Google이 결정한다. Google이 보낸
403은 부분 쓰기 대신 정직한 권한 메시지로 재매핑되므로, 거부는 거부로 읽힌다.
OAuth 토큰은 세션 쿠키(JWT)에 보관되며 서버 액션에서 쓰인다. 유일한 예외는 바로 다음에 설명할 Google의 파일 피커다 — 페이지 안에서 실행되는 Google 위젯이므로, 그것을 열면 사용자 자신의 세션용 단기 액세스 토큰이 페이지로 전달된다.
피커에서 시작한다 — ID가 결코 필요 없다
로그인한 탭은 Google에서 스프레드시트 선택으로 시작한다: Google 자체의 파일 피커가 페이지 위에 열리고, 스프레드시트를 고르면 그 ID가 패널에 안착하며 임포트가 스스로 실행된다. 고르는 행위 자체가 drive.file 아래에서 그 파일에 대한 접근 권한도 앱에 부여하므로, 한 번의 제스처가 둘 다 해낸다. 지금 다루는 시트 줄은 패널이 무엇을 가리키고 있는지 보여준다.
ID를 손으로 입력하는 것도 여전히 동작한다 — 이는 고급 — 스프레드시트 ID로 시작하기 접힘 아래로 옮겨졌으며, 이전에 저장된 ID는 예전과 정확히 똑같이 계속 동작한다. 정직한 함정은 바로 거기에 적혀 있다: Google은 사용자가 최소 한 번은 고른 적 있는 파일만 열어 주므로, 한 번도 고른 적 없는 파일의 ID는 고르기 전까지 거부된다(아래의 파일 접근 허용… 줄이 그것을 다룬다).
앱을 위해 파일 열어 주기 — 한 번만
drive.file에서는 권한이 파일 단위로 늘어난다. 앱이 아직 접근 권한이 없는 스프레드시트에 부딪히면 — 고급 아래에서 입력한 ID든, 계정을 전환한 뒤의 저장된 ID든 — 권한 오류에 부딪히는 바로 그 순간, 이미 그 스프레드시트를 찾아 놓은 상태로 Google 자체의 파일 피커를 연다. 파일을 한 번 선택하면 시작했던 임포트나 push가 스스로 마무리된다. 그 이후로 그 스프레드시트는 늘 그래왔던 것과 똑같이 동작한다.
- 미리 준비할 것이 없다. 미리 접근 권한을 부여할 필요가 없다 — 피커는 꼭 필요한 순간에, 해당 파일이 이미 지정된 채로 나타나며, 선택을 마치면 요청했던 동작이 자동으로 재시도된다.
- 재부여는 언제든 손닿는 곳에 있다. Google 패널에는 언제든 같은 피커를 여는 파일 접근 허용… 항목이 있다 — 예를 들어 다른 Google 계정으로 전환한 뒤에.
- 정직한 경계. 피커는 페이지 안에서 실행되는 Google 위젯이므로, 사용 중에는 페이지가 사용자 세션의 단기 액세스 토큰(최대 한 시간까지 유효)을 보유하며, 이 토큰은 로그인을 요구하는 동일 출처 엔드포인트에서 가져온다. 이는 아래 키 파일 경로가 페이지에 부여하는 것과 같은 종류의 신뢰다 — 앱의 엄격한 콘텐츠 보안 정책(CSP)이 이를 지켜 준다. 토큰은 저장되거나 로그로 남지 않는다.
키 파일 탭은 ID 필드를 일부러 그대로 유지한다: 서비스 계정에는 고를 수 있는 로그인 브라우징 세션이 없으므로, 시트를 그 계정에 공유해 둔 ID가 그곳에서는 여전히 정직한 진입 방법이다.
배포된 사이트에서 — 브라우저가 서명하는 서비스 계정 키 파일
Google 패널의 두 번째 탭은 서비스 계정 JSON 키 파일을 받는다. 그 키가 하는 모든 일은 사용자의 브라우저 안에서 일어난다:
- 키는 서버에 결코 닿지 않는다. 브라우저 자신이 토큰 요청에 서명하고 Google API를 직접 호출하므로, 키·서명된 요청·액세스 토큰·시트 데이터 모두 SheetForge의 서버에 닿지 않는다. 서버 측 서비스 계정 라우트는 배포된 사이트에서 기존과 똑같이 닫힌 채로 게이트된다(
501) — 이 경로는 새 능력을 하나 열지 않고도 더한다. - 키를 기억해 두는 것은 무엇을 저장하는지 정직하다. 키를 기억하도록 선택하면 파일의 텍스트는 즉시 폐기된다. 대신 남는 것은 — 그 기기에, 브라우저의 저장소 안에 — 페이지의 스크립트가 서명에는 쓸 수 있지만 다시 읽어낼 수는 없는 서명 키다. 그 브라우저 프로필을 열 수 있는 사람이라면 그래도 키를 복원할 수 있으므로, 그 기기를 키 파일 자체처럼 다뤄야 한다. 키 잊기를 누르면 열려 있는 모든 탭에서 즉시 제거되며, 앱은 Google에 현재 액세스 토큰의 폐기도 함께 요청한다.
- 같은 플랜, 같은 검증. 읽기와 쓰기는 다른 경로들과 동일한 코어 플랜, 동일한 전송 전 검증을 거쳐 실행된다.
Unity / 로컬 경로
Unity와 로컬 개발 서버가 쓰는 서비스 계정 키는 머신 로컬 경로에서 읽으며 결코 업로드되거나 번들되지 않는다 — Google 시트 설정 — 서비스 계정 및 JSON 키에서 설명한 그 키와 동일하다; Assets/ 바깥, 저장소 바깥에 두어야 한다. 저장소에는 자격 증명이 전혀 담겨 있지 않다.
Push할 때마다 드롭다운이 갱신된다
웹 앱에서 push한 뒤에는 시트의 데이터 검증 드롭다운이 자동으로 다시 쓰인다 — 모든 탭이 한 배치로, 참조 컬럼의 드롭다운은 대상 시트의 키 컬럼에 걸친 범위로 기록되므로 레코드가 추가될수록 함께 늘어난다. 존재하지 않는 시트 탭을 겨냥한 규칙은 건너뛰어지고 보고된다. 이는 에디터의 Google push가 기록하는 것과 일치한다.
어느 경로가 무엇을 하는가
| 실행 위치 | Google 자격 증명 | 읽기 | 쓰기 |
|---|---|---|---|
| Unity/로컬 | 서비스 계정 키, 머신 로컬 경로에서 읽음 | 가능 | 가능 — 정밀 셀 쓰기, 구조 재작성, Push |
| 배포된 사이트 | 로그인한 사용자의 OAuth 토큰(drive.file — 앱을 위해 연 파일들) | 가능 | 가능 — 동일한 코어 플랜 + 낙관적 잠금 검증 |
| 배포된 사이트 | 사용자가 선택한 서비스 계정 키 파일, 브라우저가 직접 사용 | 가능 | 가능 — 동일한 코어 플랜과 검증; 요청은 브라우저에서 Google로 곧장 간다 |
| 배포된 사이트 | 서버 측 서비스 계정 라우트 | — | 닫힌 채로 게이트됨(501) |
쓰기 동작은 어디서 실행하든 동일하다. 모든 경로가 코어 플랜과 전송 전 검증을 공유하기 때문이다. 오직 전송 방식 — 브라우저가 서명한 서비스 계정 토큰, 사용자별 OAuth 베어러, 또는 로컬 서버의 키 — 만 달라질 뿐이다.
관련 페이지
- Google 시트 설정 — 서비스 계정 및 JSON 키 — Unity 경로를 위한 서비스 계정과 JSON 키 만들기
- 소스, 내보내기 및 Push — 웹 쓰기 경로가 공유하는 Push 안전 체인
- SheetForge Web — 이 액세스가 자리한 브라우저 앱