OAuth와 Authentication, Authorization
by EarlyHail
Authentication vs Authorization
Authentication
유저가 있을 때, 이 유저가 진짜 유저인지 인증
하는 것
Authorization
유저가 있을 때, 이 유저가 특정 자원에 접근할 권한이 있는지
확인하는 것
예시로, 실제로나 영화에서나 건물의 특정 제한 구역에 Authorized Personnel Only
라는 문구가 붙어있는걸 볼 수 있다.
건물을 들어가는건 등록된 사용자 인증(Authenticatation)을 통해 들어갈 수 있고, 건물 내의 특정 건물은 권한 검사(Authorization)를 통해 들어갈 수 있다.
OAauth
OAuth의 용어들
-
Resource Owner
보호된 리소스에 대한 접근 권한을 부여할 수 있는 개체
ex) 자원을 소유하고 있는 사람
-
Client
Resource OWner를 대신하여 권한을 부여받아 리소스를 요청하는 응용 프로그램
ex) 개발자가 만들고 있는 서비스
-
Authorization Server
Resource Owner를 인증하고 권한을 얻은 후 Client에 Access Token을 발급하는 서버
인증을 담당하는 서버
ex) GitHub, Google 등의 인증 서버
-
Resource Server
Access Token을 사용하여 보호된 자원 제공
ex) GitHub, Google 등의 데이터 서버
OAuth를 쓰는 이유
-
인증과 권한 부여를 동시에 할 수 있음
OAuth의 ‘Auth’는 ‘Authentication’과 ‘Authorization’이다.
Resource Owner가 Client의 정보를 가지고 Authorization Server에 로그인 한다.
그 결과로 Client는 Resource Owner의 권한(Authorization)을 가지고 Resource에 접근하여 사용자 정보를 확인 후 Authenticate 할 수 있다.
-
Resource Owner(사용자) 입장에서 안전함
사용하려고 하는 서비스가 나의 어떤 자원을 접근하려고 하는지 확인 가능
-
서비스 제공자 (클라이언트)의 보안 부담감 낮아짐
보안에 민감한 사용자의 리소스(ex. PW)를 직접 관리하면 보안에 매우 신경써야함.
OAuth의 절차
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
출처 : https://tools.ietf.org/html/rfc6749
Code로 알아보는 OAuth 절차
router.get("/github", (req, res) => {
// (A) Client가 Resource Owner의 GitHub에 대한 권한 부여 요청
res.redirect(
`https://github.com/login/oauth/authorize?client_id=${process.env.GITHUB_OAUTH_CLIENT_ID}`
);
// (B) 사용자는 GitHub에 로그인하며 Client에게 권한 부여
});
router.get("/github/callback", async (req, res, next) => {
// req.query에는 Authorization Server에서 제공한 Authorization Code가 들어있음
if (req.query.error) {
// GitHub Authorization 실패 (Resource Owner가 GitHub 로그인 실패 또는 권한 부여 거부)
return;
}
const accessCode = req.query.code;
// (C) 부여된 권한(Authorization Code)을 가지고 Authorization Server에 Access Token 요청
const accessResponse = await fetch(
`https://github.com/login/oauth/access_token?client_id=${process.env.GITHUB_OAUTH_CLIENT_ID}&client_secret=${process.env.GITHUB_OAUTH_CLIENT_SECRET}&code=${accessCode}`,
{
method: "POST",
headers: {
accept: "application/json",
},
}
);
const accessResponseBody = await accessResponse.json();
// (D) AccessToken 획득
const accessToken = accessResponseBody.access_token;
// (E) Access Token을 가지고 Resource Server에 자원 요청
const profileResponse = await fetch("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${accessToken}`,
accept: "application/json",
},
});
// (F) 사용자 정보 획득
const profile = await profileResponse.json();
res.json(profile);
});
module.exports = router;
Access Token을 획득하는 방법
Authorization Grant (C) 과정을 위해 Resource Owner의 권한을 이용하여 Access Token을 얻는 방법은 4가지가 존재한다.
-
Authorization Code
-
Client는 Resource Owner를 Authorization Server로 리다이렉트 하고 Authorization Server는 인증 코드와 함께 Resource Owner를 클라이언트로 리다이렉트
-
가장 기본적인 방법 (위에서 구현한 방법)
-
Authorization Code로 브라우저 기반 로그인을 구현하고 싶다면 (A), (B) 과정을 Client에서 popup을 띄워 처리하고 Access Code를 서버에게 넘겨주고 처리하는 방법을 사용할 수 있다.
-
-
Implicit
-
브라우저 기반으로 직접 Access Token를 획득하는 방법
-
Resource Owner는 브라우저 등을 통해 Access Token을 바로 획득하여 Client에게 전달
-
Client는 Access Token을 받아 Resource Server에 접근
-
-
Access Code를 얻는 과정을 생략하기 때문에 효율성이 향상되지만 Access Token이 노출되고 Access Token을 가지고 있으면 누구나 자원에 대한 접근이 가능하기 때문에 보안상 좋지 않다.
-
-
Resource Owner Password Credentials
-
사용자 아이디, 패스워드를 이용하여 직접 Access Token을 획득
-
Resource Owner와 Client간 신뢰도가 매우 높을 경우 사용
-
-
Client Credentials
-
Client가 관리하는 자원에 접근하거나 이전의 권한에 따라 자원에 접근할 때 사용
-
보통 Resource Owner === Client인 경우 사용
-