사람 없이 구글 API를 쓰는 법 — 서비스 계정과 OAuth 이해하기
안녕하세요, 천상나타입니다.
구글 서치콘솔 API를 쓰면서 제일 처음 부딪힌 벽이 "로그인"이었어요. 브라우저 없이 코드만으로 구글 데이터를 읽으려면 사람 로그인을 대신할 뭔가가 필요한데, 그게 바로 서비스 계정입니다. OAuth가 뭔지, 서비스 계정이 어떻게 인증되는지 처음부터 정리해봅니다.
OAuth란 — "내 비밀번호를 주지 않는 위임"
OAuth를 한 문장으로 말하면, 비밀번호를 직접 넘기지 않고 권한만 위임하는 표준입니다.
우리가 "구글 계정으로 로그인" 버튼을 누르면 일어나는 일이 그거예요.
- 앱이 "이 사용자의 프로필을 읽고 싶습니다"라고 구글에 요청
- 사용자가 구글 로그인 화면에서 "허용" 클릭
- 구글이 앱에 액세스 토큰을 발급
- 앱은 그 토큰으로 허용된 것만 조회
여기서 핵심은 앱이 사용자 비밀번호를 절대 모른다는 거예요. 토큰은 기한이 있고, 허용된 범위(scope)로 제한됩니다.
서비스 계정 — 사람 대신 기계가 쓰는 계정
근데 제 경우처럼 "밤에 배치로 서치콘솔 데이터를 긁어오는 스크립트"는 사람이 로그인 버튼을 누를 수가 없어요. 이럴 때 쓰는 게 서비스 계정입니다.
구글 클라우드에서 만드는 "가짜 구글 계정"이에요. bot@my-project.iam.gserviceaccount.com 같은 이메일 형태인데, 로그인 화면이 없고 대신 JSON 키 파일로 증명합니다.

흐름은 이렇습니다.
- 키 파일 준비 — 클라우드 콘솔에서 서비스 계정을 만들고 JSON 키를 다운로드
- JWT 서명 — 코드가 키로 "나 이 계정 맞아요 + 이런 권한 줘요"라는 요청(JWT)에 서명
- 토큰 발급 — 구글이 서명을 검증하고 단기 액세스 토큰 발급
- API 호출 — 토큰을 붙여 API 요청
// googleapis 라이브러리라면 이게 전부입니다
const auth = new google.auth.GoogleAuth({
keyFile: 'service-account.json',
scopes: ['https://www.googleapis.com/auth/webmasters.readonly'],
});
const sc = google.searchconsole({ version: 'v1', auth });
실제로 해보면 — 3가지 설정
서치콘솔 API를 붙일 때 필요한 설정을 캡처로 정리하면 이렇습니다(개인정보는 가명 처리했어요).
① API 활성화 — 클라우드 콘솔에서 Search Console API를 켜줍니다.

② 서비스 계정을 서치콘솔 "사용자"로 추가 — 이게 헷갈리는 부분인데, 계정을 만들기만 해선 데이터가 안 나옵니다. 서치콘솔 설정에서 그 계정 이메일을 사이트 사용자로 등록해야 해요.

③ 스코프는 읽기 전용 — webmasters.readonly면 데이터를 "보기"만 가능하고 변경은 안 됩니다. 색인 요청 같은 쓰기까지 하려면 webmasters 스코프가 필요해요. 필요한 것만 주는 게 원칙입니다.

키 파일 관리 — 이게 제일 중요합니다
JSON 키 파일 = 서비스 계정의 비밀번호 그 자체예요. 유출되면 그 권한으로 API를 누구나 호출할 수 있습니다.
.gitignore에 무조건 추가 — 키가 커밋된 저장소는 깃헙 스캐너가 몇 분 안에 찾아냅니다- 코드에 하드코딩 금지 — 파일 경로나 환경변수로 참조
- 캡처·블로그 포스팅에 계정 이메일·프로젝트 ID도 노출 금지 — 저는 이번 글 캡처에서 전부 가명으로 치환했어요
- 노출됐다 싶으면 클라우드 콘솔에서 키를 바로 삭제하고 재발급
정리
- OAuth = 비밀번호 대신 토큰으로 권한 위임, scope로 범위 제한
- 서비스 계정 = 사람 없이 돌아가는 프로그램 전용 구글 계정, JSON 키로 인증
- 서치콘솔에선 계정 생성 → API 활성화 → 사이트 사용자 등록 3단계가 필요해요
- 키 파일은 비밀번호와 동급 — 절대 외부에 노출하면 안 됩니다
다음 글은 시리즈 마지막 — 같은 블로그가 구글에선 잘 뜨고 네이버에선 노출이 거의 없는 이유, 두 검색엔진의 구조적 차이를 분석해볼게요.
'IT > Server' 카테고리의 다른 글
| 하루 16만 요청, 무료 플랜 사이트가 죽었다 — Cloudflare Error 1027 대응기 (0) | 2026.11.14 |
|---|---|
| Bitbucket 전용 SSH Key 생성 & 설정 방법 (기존 키 유지) (0) | 2026.01.10 |
| 왜 Forward Proxy / Reverse Proxy라고 부를까? (0) | 2025.12.25 |
| HTTPS 프록시의 핵심, CONNECT 메서드란? (0) | 2025.12.25 |
| HTTP 메서드 정리: GET, POST 말고도 뭐가 있을까? (0) | 2025.12.25 |