1. 개요


OAuth 는 google, apple, facebook 등에서 제공하는 외부 서비스 연동하고자 할 때, 사용자의 개인정보나 인증관련 정보를 우리의 서비스 안에 보관하지 않고도 우리가 필요한 서비스를 사용자에게 제공해 줄 수 있는 방법입니다.

OAuth 라고 하면 오늘날에는 대부분 OAuth 2.0 이후의 OAuth를 말합니다. 때문에 이 글에서도 버전을 명시하지 않는 경우라면 OAuth는 OAuth 2.0을 가리킵니다.

이 글에서는 OAuth 인증방식 중에 널리 사용되고 있는 Authorization Code 방식을 중심으로 OAuth에 대해 알아보겠습니다.

2. 역할


OAuth 서비스의 생태계를 설명할 때 주로 등장하는 역할은 아래와 같습니다.

역할상세
Resource
Server
google, apple, facebook 등과 같이 Resource Owner의 정보를 가지고 있고 OAuth 기반의 서비스를 제공하는 서버
(Authorization
Server)
Resource Server에 대한 인증을 담당하는 서버, Resource Server의 한 기능으로 절차서의 표현에 따라서는 생략되기도 함
Resource
Owner
Resource Server 의 계정을 보유하고 있는 사용자 (google, apple, facebook 등의 서비스 이용자)
Client google, apple, facebook 등에서 OAuth를 통해 제공하는 서비스를 사용하고자 하는 서버
(대부분 우리가 구축하는 서비스의 서버-사이드, BACKEND)

3. 서비스 등록


google, apple, facebook 등에서 제공하는 외부서비스를 이용하려면  google, apple, facebook 등의 서비스 제공자에게 Client 을 등록하는 절차를 먼저 수행해야 합니다.

OAuth 서비스 제공자에 따라 상세한 스펙은 다르지만 기본적으로 아래에 해당하는 정보를 활용하게 됩니다.

용어상세비고
Client ID Authorization Server 에서 Client를 식별하기 위한 값  
Client
Secret
Authorization Server 에 Client 의 자격증명을 위한 일종의 비밀번호 해당하는 값 비공개 정보로서 외부에 노출되면 안됨
Authorized redirect URIs  Authorization Server 에 등록되는 URI로 Authorization Server 에서 Client를 식별한 뒤 authorization code를 반환할 때 사용하는 URI 정보
(Backend 에서는 해당 권한 코드로 google 서비스 이용시 사용)
서비스 등록시, 서비스 제공자에게 제공해야하는 정보
인증요청시 사전에 등록된 URI와 다른 URI를 반환될 주소로 지정하여 요청하게 되면 Authorization Server는 해당 인증요청을 비정상적 접근으로 간주하고 무시하거나 거절하게 됨

4. 주요용어


용어

설명
 
 
 
 
 
 
Challenge

 

 

Authorization Code :
Access Token과 Refresh Token을 발급받는데 필요한 코드

로그인 인증을 하면 Authorization Server가 사용자 정보와 사용자가 획득한 권한 정보를 저장하고 제공한다.
Access Token :
Resource Server(google)로부터 Resource Owner의 보호된 자원(google 계정 정보)을 획득할 때 사용되는 만료 기간이 있는 토큰

Access Token은 수명이 짧아 만료되면 Refresh Token을 Authorization Server에 전달하여 새 Access Token을 발급받는다.
Refresh Token​ : 
일정 기간 동안 다시 인증 절차(로그인)를 거치지 않고도 만료된 Access Token을 발급을 받을 수 있게 하는 토큰

Refresh Token은 외부에 노출되지 않도록 하기 위해 보통 DB에 저장하곤 한다.
Scope (optional) : 
Resource Server(google)가 OAuth를 통해 제공하는 서비스나 정보의 범위
Code :
PKCE 방식에서 코드검증에 사용되는 값
VerifierCode :
PKCE 방식에서 코드검증에 사용되는 암호화된 값

 

5. 인증방식과 인증절차


5.1. Authorization Code

OAuth 의 인증방식 중에 Authorization Code 방식을 가장 많이 사용되며 아래와 같은 특징이 있습니다.

  • Access Token 발행 전에 Authorization Code(승인코드) 교환을 수행함으로써 효율적으로 사용자(Resource Owner)의 정보를 보호할 수 있습니다.
  • Client와 Authorization Server 사이에 backend 채널을 통해 Access Token 토큰이 발급되고 교환되기 때문에 공격자가 토큰을 중간에서 가로채는 것을 막을 수 있습니다.

<Authorization Code 인증절차>

Authorization Code 인증절차에서 등장하는 주요 파라미터

Parameter

설명


client_id : 클라이언트 자격증명. Authorization Server에서 클라이언트를 등록하면 발급하는 클라이언트의 고유ID로 클라이언트의 검증에 사용. 
client_secret : 클라이언트 자격증명. Authorization Server에서 클라이언트를 등록하면 발급, 클라이언트의 비밀번호와 유사
redirect_url : Authorization Server가 권한부여 과정에서 요청에 대한 응답(Authorization Code, Access Token 등)을 보낼 url
Client에서 Authorization Server에 등록하는 Uri로 
만약 이 Uri로부터 인증을 요구하는 것이 아니라면, Resource Server는 해당 요청을 무시한다.
response_type : 권한 부여 동의 요청 시 포함되는 값으로 권한 부여 방식에 대한 설정
( API 명세에서 response_type를 "code"로 고정이라는 문구를 자주 볼 수 있다)
grant_type : Access Token 획득 요청 시 포함되는 값으로 권한 부여 방식에 대한 설정
( API 명세에서 grant_type를 "authorization_code"로 고정이라는 문구를 자주 볼 수 있다)
code : Authorization Code Grant 방식에서 Access Token요청 시 사용하는 코드로
Authorization Server로 부터 전달받은 Authorization Code를 입력한다.
expires_in : 토큰 만료 시간

 

5.2. Authorization Code with PKCE

Authorization Code 절차에 Proof Key for Code Exchange(PKCE)의 절차를 추가한 방식으로 Authorization Code(승인코드)가 탈취되었을 경우에도 Access Token을 발급받지 못하도록 안전장치를 추가한 방식입니다.

 

<Authorization Code with PKCE 인증절차>

 

붉은 색으로 표시한 부분이 Authorization Code 방식과 차이를 보이는 부분입니다.

단계적으로 Code Verifier와 Code Challenge를 교환하고 Authorization 서버에서는 이를 검증함으로써 Authorization code의 요청자와 AccessToken의 요청자가 서로일치하고 Authorization code가 외부인에게 노출되지 않았음을 검증합니다.

Code Verifier와 Code Challenge의 생성규칙은 아래와 같습니다.

구분생성 규칙비고
Code Verifier 48 ~ 128 글자수를 가진 Random String.
A-Z a-z 0-9 -._~ 문자들로만 구성됨
 
Code Challenge 선택한 Hash 알고리즘으로 Code Verifier를 Hashing 한 후 Base64 인코딩을 한 값 ex) Base64Encode(Sha256(Code Verifier))

5.3. (Legacy) implicit (암묵적승인)

Authorization Code 코드 교환의 절차를 생략하고 AccessToken을 즉시 반환받는 방법입니다.

이 방법은 보안상의 이유로 Legacy 상태로 전환되었으니 사용을 지양해야 합니다.

 

6. OAuth 2.0 클라이언트의 API 요청 예제

 

클라이언트 기준에서 보면 대표적으로 3가지의 API 요청을 할 수 있습니다.

  1. 로그인 인증 요청
  2. Access Token 발급 요청
  3. Access Token 갱신 요청

네이버와 카카오 로그인 API를 예시로 설명하겠습니다

1) 로그인 인증 요청

  • Client Id와 Redirect Uri를 전달하여 로그인 인증을 요청하고, 로그인을 완료하면 Authorization Code를 발급받는다
  • (response_type=code)

네이버 로그인 API

요청응답
https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=jyvqXeaVOVmV&redirect_uri=http%3A%2F%2Fservice.redirect.url%2Fredirect&state=hLiDdL2uhPtsftcU 
http://콜백URL/redirect?code={code값}&state={state값}

카카오 로그인 API

요청응답
GET /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code 
${REDIRECT_URI}?code=${AUTHORIZE_CODE}

 

2) Access Token 발급 요청

  • Client Id, Client Secret, Authorization Code를 이용하여 Access Token과 Refresh Token을 발급받는다.
  • (grant_type=authorization_code)

네이버 로그인 API

요청응답
https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&client_id=jyvqXeaVOVmV&client_secret=527300A0_COq1_XV33cf&code=EIc5bFrl4RibFls1&state=9kgsGTfH4j7IyAkg 
{ "access_token":"AAAAQosjWDJieBiQZc3to9YQp6HDLvrmyKC+6+iZ3gq7qrkqf50ljZC+Lgoqrg",    
"refresh_token":"c8ceMEJisO4Se7uGisHoX0f5JEii7JnipglQipkOn5Zp3tyP7dHQoP0zNKHUq2gY", 
"token_type":"bearer", 
"expires_in":"3600" }

카카오 로그인 API

요청응답
POST "https://kauth.kakao.com/oauth/token"  
-d "grant_type=authorization_code" 
-d "client_id=${REST_API_KEY}" 
--data-urlencode "redirect_uri=${REDIRECT_URI}" 
 -d "code=${AUTHORIZE_CODE}"
(client_secret는 설정 선택사항)
{ "token_type": "bearer", 
"access_token": "${ACCESS_TOKEN}", 
"id_token": "${ID_TOKEN}", 
"expires_in": 7199, 
"refresh_token": "${REFRESH_TOKEN}", 
"refresh_token_expires_in": 86399, 
"scope": "profile_image openid profile_nickname" }

 

3) Access Token 갱신 요청

  • Client Id와 Refresh Token을 전달하여 만료된 Access Token을 새로 받는다.

네이버 로그인 API 

요청응답
https://nid.naver.com/oauth2.0/token?grant_type=refresh_token&client_id​=jyvqXeaVOVmV&client_secret=527300A0_COq1_XV33cf&refresh_token=c8ceMEJisO4Se7uGCEYKK1p52L93bHXLn 
{"access_token":"AAAAQjbRkysCNmMdQ7kmowPrjyRNIRYKG2iGHhbGawP0xfuUhz+R2CmUqnN0lGuOcbEw6iexg", 
"token_type":"bearer", 
"expires_in":"3600" }

카카오 로그인 API

요청응답
curl -v -X POST "https://kauth.kakao.com/oauth/token"
-d "grant_type=refresh_token" 
-d "client_id=${REST_API_KEY}" 
-d "refresh_token=${USER_REFRESH_TOKEN}"
{ "access_token":"${ACCESS_TOKEN}", 
"token_type":"bearer", 
"refresh_token":"${REFRESH_TOKEN}"}

7. Access Token 획득 후 프로세스

 

토큰 보관

  • 애플리케이션은 리소스 서버의 API를 호출하기 위하여 인증(로그인)을 하고 액세스 토큰을 얻습니다.​​
  • 클라이언트는 발급받은 Access Token과 Refresh Token을 안전한 공간에 보관해야합니다.

API 호출

  • 액세스 토큰은 앱의 신원과 권한을 증명하며, 각 API 요청과 함께 액세스 토큰을 리소스 서버의 API에 제출해야합니다.
  • 클라이언트는 API 을 요청할 때  Authorization header에 Access token을 담아서 보냅니다.​
  • 발급받은 액세스 토큰은 사용자 정보 가져오기와 같은 로그인이 필요한 API를 호출할 때 사용합니다.
  • 일반적인 서비스 API를 호출할 수 도 있고, 처음 로그인 완료 후 사용자 정보 요청을 통해 필요한 사용자 정보를 받아 서비스 회원 가입 및 로그인 등을 처리할수도 있습니다.

토큰 재발급

  • Refresh Token은 Access Token이 만료되었다는 응답을 받은 경우 Access Token 재발급을 위해 사용합니다.
  • 클라이언트가 Refresh Token을 Authorization Header에 추가해보내면
  • Auth Server는 DB에 기록되어 있는 사용자의 Refresh Token과 동일한지 검증한 후 새로운 Access Token을 발급합니다.
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기