서비스에 직접 회원가입하지 않고도 기능을 사용할 수 있게 해주는, "구글로 로그인하기" 혹은 "페이스북으로 로그인하기" 등의 기능이 존재합니다.
어떠한 애플리케이션에서 "구글로 로그인하기" 를 한다고 합시다.
그럼 이 애플리케이션은 구글에 저장된 사용자 정보에 접근할 수 있어야 합니다.
이렇듯 애플리케이션이 타사 서비스에서 정보 접근 권한을 얻도록 하는 표준 프로토콜을 OAuth
라고 합니다.
즉, 사용자가 내 서비스에서 회원가입하는 과정을 거치지 않고도 타 서비스를 활용해서
인증과 인가 절차를 처리하도록 하는 것이죠.
공식문서에서 설명하는 프로토콜 구조 이미지입니다.
다음과 같은 과정을 거칩니다.
resource owner
(ex. 구글)에게 권한 요청resource owner
가 요청 승인authorization server
에서 access token
을 받음access token
으로 resource server
에서 정보 접근권한을 얻어와 토큰을 받고, 토큰을 이용하여 사용자 정보에 접근합니다.
실제 타사 서비스를 이용하여 OAuth
를 적용한 로그인을 구현해봅시다.
대부분 다음과 같은 과정을 거칩니다.
타사 서비스를 사용할 OAuth App 으로 자사 서비스 등록
등록한 OAuth App 에 부여되는 값. Client ID 는 공개해도 괜찮지만 Client Secret 은 비밀로 유지해야 함❗
인가 코드가 Redirect URL 로 전달됨
위 링크 참고해서, OAuth App 에 권한을 받아옵시다.
권한을 받는 웹앱 플로우는 다음과 같습니다.
Users are redirected to request their GitHub identity
Users are redirected back to your site by GitHub
Your app accesses the API with the user's access token
- 처음에 GitHub 사용자 인증을 위한 링크로 이동
(깃허브 로그인)- 다시 원래 사이트로 리다이렉트
- 앱은 액세스 토큰을 받아서 API 사용
OAuth App 에 나의 서비스를 등록해줍시다.
깃허브 세팅 의 OAuth Apps
에서 새로운 OAuth App 을 생성합니다.
Homepage URL
과 Authorization callback URL
을 지정해줍니다.
Homepage URL
은 어플리케이션의 URL,
Authorization callback URL
에는 app 이 권한을 얻은 후 이동할 URL 을 입력합니다.
여기서 Client ID 와 Client Secret 값을 얻을 수 있습니다.
.env
에 저장해둡니다.
이제 OAuth app 을 만들었으면 아래 공시문서를 따라하여
OAuth 앱(나의 앱)에 권한을 부여하도록 할 수 있습니다.
과정은 다음과 같습니다.
GET https://github.com/login/oauth/authorize
이때, 파라미터로 client_id
를 넘겨줘야 합니다.
OAuth app 을 만들 때 Client ID 값도 같이 생성됐었죠? 그 값을 입력해주면 됩니다.
공식문서를 보면 다양한 파라미터가 존재하고 그 값에 따른 옵션이 설명되어 있습니다.
이 중 scope
파라미터로 얻어올 토큰의 권한을 제어할 수 있습니다.
사용자의 정보를 어디까지 열람해서 사용할지 결정한다고 보면 됩니다.
scope
로 넘겨준 값에 따라 접근 가능한 정보의 범위가 결정됩니다.
scope
권한은 위 링크에서 살펴봅시다...
const baseUrl = "https://github.com/login/oauth/authorize";
const config = {
client_id: process.env.GH_CLIENT,
allow_signup: false,
scope: "read:user user:email",
};
const params = new URLSearchParams(config).toString();
const finalUrl = `${baseUrl}?${params}`;
return res.redirect(finalUrl);
위처럼 https://github.com/login/oauth/authorize
에 config
처럼 파라미터 설정을 해서 최종 URL 을 만들어주고 거기로 GET 요청을 해주면 됩니다.
code
파라미터와 access token
교환하기1번에서 GET 요청을 해주면 설정해둔 Authorization callback URL
로 code
파라미터와 함께 리다이렉트 됩니다.
이제 이 code
를 가지고 Client ID 와 Client Secret 을 입력하여
아래 URL 로 POST 요청을 해주면 access token
을 얻을 수 있습니다.
POST https://github.com/login/oauth/access_token
code
의 유효기간은 10분이니 그 안에 토큰과 교환해줘야 합니다.
const baseUrl = "https://github.com/login/oauth/access_token";
const config = {
client_id: process.env.GH_CLIENT,
client_secret: process.env.GH_SECRET,
code: req.query.code,
};
const params = new URLSearchParams(config).toString();
const finalUrl = `${baseUrl}?${params}`;
const tokenRequest = await (
await fetch(finalUrl, {
method: "POST",
headers: {
Accept: "application/json",
},
})
).json();
URLSearchParams
로 config
의 파라미터를 설정한 최종 URL 을 만듭니다.
그 후 fetch
로 해당 URL 에 POST 요청을 해줍니다.
헤더에 Accept: application/json
을 추가해주면 해당 형식으로 응답받을 수 있습니다.
응답은 tokenRequest
로 받으며, 토큰은 access_token
이라는 이름으로 받아옵니다.
2번에서 토큰을 얻어왔으니, API 를 이용하여 정보를 얻어올 수 있습니다.
헤더에 Authorization: Bearer OAUTH-TOKEN
을 포함해주고 API URL 에 GET 요청을 해줍니다.
Authorization: Bearer OAUTH-TOKEN
GET https://api.github.com/user
위처럼 유저 정보를 얻어올 수 있습니다.
const { access_token } = tokenRequest;
const apiUrl = "https://api.github.com";
const userData = await (
await fetch(`${apiUrl}/user`, {
headers: {
Authorization: `Bearer ${access_token}`,
},
})
).json();
이렇게 얻어온 유저 정보로 DB 와 대조하여 로그인하거나, 새로운 유저를 생성하거나 할 수 있습니다.
로그아웃을 위해서는 세션에 기록된 유저 정보를 삭제해줘야겠죠.
req.session.destroy();
위 코드를 사용하면 세션 정보를 삭제할 수 있습니다.