Google Calendar API를 앱에 통합하는 방법
목차
단일 API로 모든 캘린더 통합하기
한국어 단일 API를 사용하여 모든 캘린더 제공업체를 애플리케이션에 통합하세요. 신용카드는 필요하지 않습니다.
이 가이드에서는 Google Cloud 프로젝트 설정, 필요한 범위(scopes), 주의할 점, 실제 인증 예제까지 포함하여 Google Calendar API를 앱에 통합하는 방법을 자세히 설명합니다.
사전 요구사항
이 가이드는 이메일 주소와 Google Cloud 프로젝트를 설정할 때 사용할 준비된 도메인, 약간의 코딩 배경, 그리고 무엇을 만들고자 하는지에 대한 대략적인 아이디어가 있다고 가정합니다.
Google Calendar API를 한 번도 사용해본 적이 없고, 앱에 Google Calendar API를 통합하는 데 필요한 모든 단계를 익히고 싶은 경우에도 이 가이드는 유용합니다.
Google Calendar API를 앱에 사용하는 방법과 통합하는 방법
1. Google Developer Console 가입하기
Google Developer Console 계정이 없다면 https://console.cloud.google.com/에서 하나 생성하세요.
2. 기존 Google Cloud 프로젝트를 선택하거나 새로 만들기
Google Cloud는 개발자와 조직이 여러 개의 프로젝트를 가질 수 있도록 허용합니다. 아래의 작업을 수행할 때 올바른 프로젝트를 선택했는지 반드시 확인하세요.
화면 좌측 상단의 프로젝트 드롭다운을 클릭하세요. 이름은 보통 프로젝트 이름과 일치합니다.

기존 프로젝트를 선택하거나, 모달 오른쪽 상단의 _“New Project”_를 클릭하여 새 프로젝트를 생성하세요.

3. Google Calendar API 서비스 활성화하기
계정을 생성하고 올바른 프로젝트에 있는지 확인한 후, 다음 단계에 따라 Google Calendar API 서비스를 활성화하세요:
- Google Cloud Console로 이동하세요
- “APIs & Services”_를 클릭하세요

- “Enable APIs and services”_를 클릭하세요

- “Google Calendar API”_를 검색하세요

- “Enable”을 클릭하여 서비스를 활성화하세요.

4. OAuth 동의 화면 설정하기
Google Calendar API 서비스를 활성화한 후, 다음 단계는 OAuth 동의 화면을 설정하는 것입니다. OAuth 동의 화면은 사용자가 앱과 자신의 캘린더를 연결할 때 보게 되는 인터페이스입니다. 보통 앱 로고, 이름, 요청 권한 등을 볼 수 있습니다.
- "OAuth Consent Screen" 탭을 클릭하세요.

- "Get Started"를 클릭하세요.

- “App Information” 섹션을 작성하세요. 이 섹션에서는 앱 이름과 고객 지원 이메일을 입력해야 합니다.

- 대상을 선택하세요. 대상은 내부 또는 외부일 수 있습니다. 앱이 공개되지 않고 조직 내 사용자만 캘린더를 연결할 수 있는 경우 내부를 선택하세요. 일반 사용자도 로그인할 수 있는 경우에는 외부를 선택하세요.

- 연락처 정보를 입력하세요. Google은 프로젝트 변경 사항을 알려줄 이메일을 요구합니다.

- "Agree to the Google API Services: User Data Policy" 체크박스를 선택하세요.

- “Create”_를 클릭하세요.

5. OAuth 클라이언트 생성하기
OAuth 동의 화면 설정이 완료되면, 프로젝트에 대한 OAuth 클라이언트를 생성할 수 있습니다. “Clients” 탭을 클릭한 후, ‘Create Client’를 클릭하세요.
또는 개요 페이지에서 _“Create OAuth Client”_를 클릭해도 됩니다.

앱이 실행될 각 플랫폼에 대해 클라이언트를 생성할 수 있습니다. 예를 들어 웹 앱과 iOS 앱을 모두 개발 중이라면 각 플랫폼에 대해 별도의 OAuth Client ID를 생성해야 합니다.

이 예제에서는 “Web Application” 클라이언트를 생성하고 “Web Client”라고 이름 붙이겠습니다.

이 단계에서는 승인된 JavaScript 출처 및 리디렉션 URI도 설정합니다.
Authorized JavaScript origins 입력란에는 웹 앱을 호스팅하는 도메인/URL을 입력하세요. 예: myapp.domain.com

Authorized redirect URLs에는 Google 인증 후 사용자를 리디렉션할 모든 URL을 입력하세요. 이 URL에는 인증 코드가 함께 포함되며, 반드시 프로토콜을 포함해야 합니다.

이 앱이 개발 단계에서 사용될 수 있으므로 localhost 리디렉션 URL도 화이트리스트에 추가해야 합니다. 이 예제에서는 localhost 리디렉션 URL도 화이트리스트에 추가합니다.
모든 필드를 입력한 후 “Create”를 클릭하세요. 그러면 Google이 모달을 열고 Client ID와 Client Secret을 표시합니다. 이 필드는 안전한 장소에 복사하여 저장하세요 (예: .env 파일, 이후 인증 흐름에서 사용됨). JSON 파일을 다운로드하여 1Password와 같은 비밀 관리자에 저장할 수도 있습니다.

Client Secret을 포함하는 JSON 파일을 다운로드하거나 복사하여 안전한 곳에 저장하세요. 모달이 닫히면 Client Secret을 다시 복사할 수 없습니다.
6. 테스트 용도로 사용자 추가하기
로컬에서 앱을 개발할 때, Google Calendar 계정을 연결하려면 앱에 일부 테스트 사용자를 화이트리스트에 추가해야 합니다. 이는 앱이 외부용이며 아직 Google의 승인을 받지 않았기 때문입니다.
테스트 사용자를 추가하려면 다음 단계를 따르세요:
- “Audience” 탭을 클릭하세요.

- “Test Users” 섹션이 나올 때까지 스크롤하세요.

- “Add Users”를 클릭하고 사용자의 이메일을 입력하세요.

7. 사용할 캘린더 범위(scopes) 추가하기
Google Calendar를 앱에 통합하려는 사용 사례에 따라, 사용자가 Google Calendar 계정을 인증할 때 요청할 다양한 범위를 선택할 수 있습니다.
범위는 사용자로부터 앱에서 사용할 수 있도록 요청하는 권한이며, 앱이 Google 계정의 비공개 데이터에 접근할 수 있게 합니다. 예: 캘린더 목록 조회, 일정 보기 등
Google은 범위를 민감한 범위와 비민감한 범위로 구분합니다. 민감한 범위를 추가하면 앱을 Google에 제출하여 검증을 받아야 합니다. 이미 검증받은 앱에 추가로 민감한 범위를 추가하는 경우에도 검증이 필요합니다.
앱이 제대로 작동하는 데 필요한 모든 범위를 입력한 후, 각 범위에 대한 정당화 설명과 데모 영상을 반드시 제출해야 합니다. 이는 앱을 Google에 제출할 때 요구됩니다.
범위를 관리하려면 다음 단계를 따르세요:
- "Data Access" 탭을 클릭하세요.

- "Add or remove scopes"를 클릭하세요

- 이름이나 값으로 범위를 검색한 후 추가하세요.

8. Google Calendar API 익히기
Google Client App 설정을 완료하고 사용자가 캘린더를 연결할 수 있도록 모든 정보를 입력했다면, 이제 Google Calendar API에 익숙해질 필요가 있습니다.
Google Calendar API 개요 페이지를 방문해 주요 엔드포인트 (예: Events, Calendar 등)를 확인해보세요.
9. 하나의 API로 여러 캘린더 제공자를 통합하려면 Unified Calendar API 사용
Google Calendar만 통합하려는 경우 이 단계를 건너뛰어도 됩니다. 그러나 여러 캘린더 제공자를 지원할 계획이라면, Unified Calendar API를 사용하는 것이 좋습니다. 이 API는 모든 캘린더 제공자를 위한 통합 API를 제공합니다.
Unified Calendar API를 사용하면 한 번의 통합으로 모든 캘린더 제공자를 지원할 수 있습니다. 향후 Outlook을 지원하게 되는 경우에도 별도의 코드를 작성하지 않고 통합을 추가할 수 있습니다.
또한, 여러 개의 통합을 유지 관리할 필요가 없고, API 변경사항이나 새로운 캘린더 API를 배우는 데 시간을 쓸 필요가 없습니다.
Google Calendar 인증 흐름 예시
아래 플로우 차트는 사용자가 자신의 Google Calendar를 앱에 연결할 수 있도록 하는 간단한 Google Calendar OAuth 흐름을 보여줍니다.

Google은 Node.js, Python 등 다양한 클라이언트를 제공하지만, 여기서는 단순화를 위해 HTTP 호출과 TypeScript만 사용하여 인증 흐름을 설명하겠습니다.
클라이언트 측 (UI)
첫 번째 부분은 클라이언트/UI 측으로, 여기서는 “Connect Google Calendar” 버튼을 렌더링합니다.
const googleOauthUrl = getGoogleOAuthUrl()
<button href="googleOauthUrl" rel="noopener noreferrer"> Connect Google Calendar </button>
const SCOPES = [
"openid",
"email",
"<https://www.googleapis.com/auth/calendar.calendarlist>",
"<https://www.googleapis.com/auth/calendar.events>",
"<https://www.googleapis.com/auth/calendar.readonly>",
// add more scopes as needed
];
export interface ClientState {
session: Session;
returnUrl?: string;
}
export function stateToB64(session: ClientState): string {
return encode(JSON.stringify(session));
}
export function getGoogleOAuthUrl(
state: ClientState,
) {
const params = new URLSearchParams({
client_id: process.env.GOOGLE_CLIENT_ID || "",
redirect_uri: `${getHostName()}/api/connect/google`, // change the redirect URL as needed
response_type: "code",
scope: SCOPES.join(" "),
prompt: "consent",
access_type: "offline",
state: stateToB64(state),
});
return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
}
prompt 매개변수는 none, consent, select_account 중 하나의 값을 가질 수 있습니다.
consent는 사용자가 이전에 인증한 캘린더가 있더라도 다시 인증 화면을 표시하고자 할 때 사용됩니다. 예: 새로운 범위를 추가했을 때
select_account는 사용자가 계정을 선택하도록 유도할 때 사용됩니다.
none은 인증 또는 동의 화면을 표시하지 않도록 합니다.
API 측 (백엔드)
다음으로, Google 서버로부터 코드를 받아 토큰으로 교환하는 API 핸들러를 구현합니다.
const SCOPES = [
"openid",
"email",
"<https://www.googleapis.com/auth/calendar.calendarlist>",
"<https://www.googleapis.com/auth/calendar.events>",
"<https://www.googleapis.com/auth/calendar.readonly>",
// add more scopes as needed
];
export interface ClientState {
session: Session;
returnUrl?: string;
}
export function stateToB64(session: ClientState): string {
return encode(JSON.stringify(session));
}
export function getGoogleOAuthUrl(
state: ClientState,
) {
const params = new URLSearchParams({
client_id: process.env.GOOGLE_CLIENT_ID || "",
redirect_uri: `${getHostName()}/api/connect/google`, // change the redirect URL as needed
response_type: "code",
scope: SCOPES.join(" "),
prompt: "consent",
access_type: "offline",
state: stateToB64(state),
});
return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
}
Google ID 토큰을 디코드하거나, 코드를 토큰으로 교환하거나, 상태를 base64로 인코딩/디코딩하는 등의 기능은 유틸리티 함수로 따로 구성하는 것을 권장합니다.
export async function exchangeCodeForTokens(code: string) {
const data = new FormData();
data.append("code", code);
data.append("client_id", process.env.GOOGLE_CLIENT_ID || "");
data.append("client_secret", process.env.GOOGLE_CLIENT_SECRET || "");
data.append("redirect_uri", `${getHostName()}/api/connect/google`); // your URL
data.append("grant_type", "authorization_code");
try {
const result = await fetch("<https://oauth2.googleapis.com/token>", {
method: "POST",
body: data,
});
const json = await result.json();
if (json.error) throw json;
const parsed = responseSchema.parse(json);
return parsed;
} catch (e) {
console.error("Exchange failed");
throw e;
}
}
export function decodeIdToken(idToken: string) {
const data = jwt.decode(idToken);
if (typeof data === "string" || !data?.email) {
throw new Error(`Could not parse id_token: ${idToken}`);
}
return data;
}
function isError(query: Record<string, any>): query is ErrorParams {
return Boolean(query.error);
}
export function stateFromB64(encoded: string): ClientState {
const str = decode(encoded);
return JSON.parse(str) as ClientState;
}
위 구현에서 사용된 process.env.GOOGLE_CLIENT_ID와 process.env.GOOGLE_CLIENT_SECRET 환경 변수는 5단계에서 생성한 Client ID와 Client Secret입니다. OAuth 클라이언트를 생성할 때 반드시 복사해두세요. 모달을 닫으면 Client Secret을 다시 복사할 수 없습니다.
Google Calendar API 통합 시 주의사항
- 검증에는 몇 주가 걸릴 수 있으므로 출시 전에 여유 있게 계획하세요. Google의 승인 과정은 시간이 걸릴 수 있으며, 처음 제출할 때 거절당하는 경우가 많습니다. 일정에 이 지연을 반영하고 모든 관계자에게 알리세요.
- 웹훅은 약 24시간 후에 만료되므로 항상 갱신하세요. 캘린더 변경을 감지하기 위해 웹훅을 등록할 수 있지만, 24시간 후에 만료되므로 갱신해야 합니다. 만료 20분 전쯤 감지하여 갱신하는 크론 작업을 설정하세요.
- 필요한 범위만 요청하세요. 향후 기능을 대비해 많은 범위를 요청하고 싶을 수 있지만, 앱 기능에 꼭 필요한 범위만 요청하는 것이 좋습니다. Google은 검증 과정에서 매우 엄격하기 때문에, 불필요한 범위가 있으면 앱이 거절될 수 있습니다. 또한 사용자는 앱 기능과 관련 없는 권한 요청에 거부감을 가질 수 있습니다.
- 쿼터와 속도 제한을 처리하세요. Google은 분당 프로젝트당, 그리고 사용자당 쿼터 제한이 있습니다. 이를 초과하면 403 (usageLimits) 또는 429 (rateLimitExceeded) 오류가 반환됩니다. 지수 백오프 전략 등으로 이를 처리하세요.
- 개인 데이터를 로그에 남기지 않도록 주의하세요. 데이터 로깅은 괜찮지만, 이벤트 설명, 참석자 이메일 등의 개인 데이터를 제거하세요.
OneCal Unified Calendar API로 여러 캘린더 제공자 통합
OneCal은 지금까지 Google Calendar, Outlook, iCloud 간 수백만 개의 이벤트를 동기화해 왔습니다. 우리는 다양한 캘린더 제공자를 통합하는 데 필요한 사항, 각 API의 특성, 그리고 원활한 구현을 위한 노하우를 알고 있습니다.
그래서 우리는 Outlook, Google Calendar, iCloud Calendar를 즉시 지원하는 강력하고 사용하기 쉬운 Unified Calendar API 제품을 개발했습니다.
무료로 시작하여 Unified Calendar API를 테스트하고 기능을 확인한 후, 이후에 업그레이드를 결정할 수 있습니다.
자주 묻는 질문
Google OAuth 클라이언트에 테스트 사용자를 추가해야 하는 이유는 무엇인가요?
검증되지 않은 외부 앱은 앱이 개발 중이고 Google의 승인을 받기 전까지는 화이트리스트에 등록된 테스트 계정만 사용할 수 있습니다.
Google Calendar 웹훅은 얼마나 오래 활성화되나요?
푸시 알림 구독은 약 24시간 후에 만료되므로, 만료 전에 백엔드에서 갱신해야 합니다.
나중에 Outlook이나 iCloud 캘린더를 쉽게 추가할 수 있는 방법이 있나요?
네. OneCal Unified Calendar API와 같은 통합 캘린더 API를 사용하면 Google, Outlook, iCloud를 하나의 API로 통합할 수 있어, 별도의 통합 및 유지보수에 드는 시간과 비용을 절감할 수 있습니다.
백그라운드 작업에는 “offline_access”가 필요한가요?
네. 동의 URL에 access_type=offline을 추가하면 리프레시 토큰이 반환되어, 사용자가 없는 경우에도 서버에서 API를 호출할 수 있습니다.