0%

OAuth 2.0 프로토콜

  • 사용자가 usernames, passwords, 그리고 기타 개인적인 정보를 가지고 특정 서비스에 저장된 자신의 데이터를 다른 서비스에서 접근할 수 있도록 허락해주는 프로토콜
  • e.g. 구글의 서비스에서 관리되고 있는 사용자의 데이터를 다른 서비스가 접근할 수 있도록 구글 API를 제공

특징

  • 여러 장치를 통해 시시각각 바뀌는 사용자의 연락처 정보를 실시간으로 업데이트 받을 수 있음
  • 타 서비스에 저장된 사용자 데이터를 접근해도 되는지 사용자에게 명시적으로 허락을 받음

OAuth 2.0 flow for JavaScript: implicit grant flow

  • Implicit Grant
  • 자바스크립트 라이브러리로 개발되는 SPA에서는 implicit grant 방식이 많이 사용됨
  • user가 present 할 때만 API에 접근 가능하며, 기밀 정보는 따로 저장되지 않음
  1. 사용자는 API를 제공받고자 하는 서비스에 로그인 한 후, API를 사용하고자 하는 어플리케이션에서 요청하는 권한을 확인하고, 해당 권한을 허용한다.
  2. Google Authorization Server는 사용자를 사전에 등록된 redirect uri 로 리다이렉트 시키면서 access token 을 애플리케이션에 보낸다.
  3. 어플리케이션은 이 access token 을 이용해서 구글 API를 호출하여 원하는 정보를 얻는다.

Workflow

  1. Request : 클라이언트 어플리케이션은 Google Authorization Server에 access token 을 요청하고,
  2. Response : response로부터 token 을 추출한다.
  3. Validation : 이후 접근하고자 하는 Google API에 token 을 보낸다.

oauth2.0_javascript

Example: Google People API

  1. 구글 API를 호출하기 위해서는 가장 먼저, 구글에 API를 사용하고자 하는 어플리케이션을 클라이언트로 등록하고 client_id 를 발급받아야 한다.

    • 구글 API 콘솔 에서 프로젝트를 생성 → 사용자 인증 정보 만들기 에서 OAuth 클라이언트 ID를 선택 → 웹 어플리케이션 → 승인된 리디렉션 URI 설정 (e.g. [http://localhost:3000/](http://localhost:3000/) ) → 클라이언트 ID 생성
  2. Google Authorization Server에 접속하여 사용자 token 을 받아야 한다.

    • CLIENT_ID: 위에서 발급받은 클라이언트 ID
    • AUTHORIZE_URI: 구글에서 OAuth를 제공하는 기본 URI
    • queryStr: 위 AUTHORIZE_URI에 붙일 사용자 개인 정보 (쿼리), URL 생성용
      • client_id
      • redirect_uri: 실습 애플리케이션은 페이지가 하나 밖에 없는 SPA이기 때문에, 현재 URL을 redirect_uri로 설정
      • response_type: 어떤 OAuth 방식을 사용하는지를 결정하는 속성으로, token 으로 설정하면 implicit grant 방식이 적용
      • scope: 사용자의 어떤 데이터와 어떤 작업에 대한 권한을 요청하는지, 즉 어떤 구글 API를 요청하는지
    • loginUrl: AUTHORIZE_URIqueryStr을 붙여 만든 구글 로그인 authorization URL
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const CLIENT_ID = "YOUR CLIENT ID";
    const AUTHORIZE_URI = "https://accounts.google.com/o/oauth2/v2/auth";

    const queryStr = qs.stringify({
    client_id: CLIENT_ID,
    redirect_uri: window.location.href,
    response_type: "token",
    scope: "https://www.googleapis.com/auth/contacts.readonly"
    });

    const loginUrl = AUTHORIZE_URI + "?" + queryStr;
  3. Google Authorization Server가 redirect URIaccess token을 보내주면, 이를 이용해 token validation을 진행한다.

    • access token은 redirect uri의 hash 부분에 포함되므로, DOM의 Location API인 window.location.hash 를 이용해 가져온다.
    • 만약 access token이 없을 경우, grant server URL로 이동한다.
    1
    2
    3
    4
    5
    6
    const { access_token } = qs.parse(window.location.hash.substring(1));

    if (!access_token) {
    window.location.assign(loginUrl);
    return null;
    }
  4. access token을 이용해 구글 API를 호출한다.

    • Bearer 문자열을 access token 앞에 붙여 Authorization header로 넘긴다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const PEOPLE_URI = "https://people.googleapis.com/v1/contactGroups";

    useEffect(() => {
    fetch(PEOPLE_URI, {
    headers: { Authorization: "Bearer " + access_token }
    })
    .then((res) => res.json())
    .then((data) => setContactGroups(data.contactGroups));
    }, [access_token]);

전체 코드

qs
npm 패키지: A querystring parsing and stringifying library with some added security.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import React, { useState, useEffect } from "react";

import qs from "qs";

const CLIENT_ID = "YOUR CLIENT ID";
const AUTHORIZE_URI = "https://accounts.google.com/o/oauth2/v2/auth";
const PEOPLE_URI = "https://people.googleapis.com/v1/contactGroups";

const queryStr = qs.stringify({
client_id: CLIENT_ID,
redirect_uri: window.location.href,
response_type: "token",
scope: "https://www.googleapis.com/auth/contacts.readonly"
});

const loginUrl = AUTHORIZE_URI + "?" + queryStr;

const App = () => {
const { access_token } = qs.parse(window.location.hash.substring(1));
const [contactGroups, setContactGroups] = useState([]);

useEffect(() => {
fetch(PEOPLE_URI, {
headers: { Authorization: "Bearer " + access_token }
})
.then((res) => res.json())
.then((data) => setContactGroups(data.contactGroups));
}, [access_token]);

if (!access_token) {
window.location.assign(loginUrl);
return null;
}

return (
<>
<h2>Contact Groups</h2>
<ul>
{contactGroups &&
contactGroups.map(({ resourceName, name, memberCount }) => (
<li key={resourceName}>
{name} ({memberCount})
</li>
))}
</ul>
</>
);
};

export default App;

Reference

OAuth 2.0으로 구글 API 호출하기

OAuth 2.0 Flow: Client-side web apps | YouTube Data API

  • OAuth 2.0 프로토콜 문서

Using OAuth 2.0 to Access Google APIs | Google Identity

  • OAuth 2.0 JavaScript 문서

OAuth 2.0 for Client-side Web Applications | Google Identity

  • Google People API 문서

Method: contactGroups.get | People API | Google Developers