❓ 이 글 왜 씀?
토이프로젝트로 킹받즈 라는 웹사이트를 만들었는데 블로그도 쓰고 공부도 하고 웹사이트 업그레이드도 시켜볼 겸 쓰기로 함
주의 아직 완성 글 아님 아래 사이트에 oauth 업데이트도 아직 안했음 글 다 쓰고 할 예정
👇 그 웹사이트
별걸 다 시상하는 킹받즈
🏆오늘도 수고한 친구에게 특별한 상을 주세요!
takingprize.com
sns 공유를 목적으로 만든 웹사이트이니만큼 모바일 웹 기준으로 UI를 잡았다.
Oauth에 대한 개념, 코드 구현의 예시는 다 이 사이트로 설명 할 예정
📌 Oauth의 개념
Open Authorization의 약자로 인터넷 사용자들이 비밀번호를 제공하지 않고, 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근권한을 부여할 수 있는 공통적인 수단으로 사용되는, 접근 위임을 위한 개방형 표준이다.
웹사이트에 비밀번호 입력 없이 접근 권한을 부여해 줄 수 있는 프로토콜
사용하는 웹사이트마다 개인정보를 입력하게되면 보안이 취약하다. 이 때문에 트위터의 주도하에 OAuth 1.0이 탄생하게 되었다.
📌Oauth 2.0
⚡ Oauth 1.0과 달라진 점
- 기능의 단순화, 기능과 규모의 확장성을 지원
- https 암호화 필수
- 1.0은 인증방식이 한가지였지만, 2.0은 다양한 인증방식을 지원
- api 서버에서 인증서버와 리소스 서버 분리
📚 Oauth 2.0 구성
용어 | Description | 예시 |
Resource owner | 사용자 | 킹받즈에 가입한 유저들 |
Client | Resource Server에서 자원을 사용하는 애플리케이션 | 킹받즈 웹사이트 |
Resource Server(API 서버) | 자원(Resource owner의 개인정보)을 호스팅하는 서버 | 구글의 API 서버 |
Authorization Server (인증 서버) | 사용자의 동의를 받아서 권한을 부여하는 서버. Client의 접근 자격을 확인하고 Access Token을 발급하여 권한을 부여. | 구글의 인증 서버 |
Access Token | 자원에 대한 접근 권한을 Resource Owner가 인가하였음을 나타내는 자격증명 | |
Refresh Token | Authorization Server는 Access Token과 Refresh Token을 함께 발급한다. Access Token은 보안상 만료 기한이 있어 만료되면 재 로그인을 해야한다. Refresh Token을 통해 Access Token을 재발급 받아 재 로그인 할 필요없게끔 한다. Authorization Server에서만 사용된다. |
📚 Oauth 의 인증방식
- Authrozation Code Grant
- 권한 부여 승인을 위해 자체 생성한 Authorization Code를 전달하는 방식
- 많이 쓰이고 기본이 되는 방식
- 간편 로그인 기능에서 사용되는 방식으로 클라이언트가 사용자를 대신하여 특정 자원에 접근을 요청할 때 사용되는 방식
- Refresh Token의 사용이 가능
- Implicit Grant
- 권한 부여 코드 없이 사용자 자격 증명을 교환하는 방식
- 보안에 취약함
- javascript 에서 사용하기 위해 만들어졌다고 함 ( 특정 상황에서만 사용)
- Password Credentials Grant
- Client에 ID/PW를 저장해 놓고, ID/PW로 직접 accesstoken을 받아오는 방식
- API 서비스의 공식 어플리케이션이나 믿을 수 있는 Client에 한해서 사용하는 것을 추천
- Client Credentials Grant
- 클라이언트가 컨텍스트 외부에서 액세스 토큰을 얻어 특정 리소스에 접근을 요청할때 사용
📌Oauth 2.0 동작 방식 (With Google Login)
Resource Owner(웹사이트 사용자)는 킹받즈에 로그인을 하고싶은 유저가 될 것이고
Client(웹사이트)는 킹받즈 사이트 이다.
나는 구글 로그인을 사용할 것이니까 Authorization Server와 Resource Server는 Google이다.
인증방식은 Authrozation Code를 부여받는 Authrozation Code Grant에 해당한다.

📚 1, 2 로그인 요청
웹사이트 사용자가 킹받즈 사이트의 구글로그인 버튼을 누른다.
킹받즈 사이트는 사용자의 브라우저를 Authorization Server로 전송한다.
나의 경우 프론트엔드에서 구글로그인 버튼 클릭 시 요청 url(Authorization Url)로 이동한다.
Authorization Url
https://accounts.google.com/o/oauth2/v2/auth
요청 데이터 (query string)
response_type : code
client_id : 발급받은 Client Id
redirect_uri : 구글 인증 처리 후 redirect 할 uri (미리 구글 클라우드 콘솔에서 등록)
scope : 리소스 접근 권한
📚 3, 4 로그인 페이지 제공, ID/PASSWORD 제공
1~2에서 요청한 Url로 구글에서 제공하는 로그인 페이지로 이동한다.
사용자는 구글 인증을 진행한다.
📚 5, 6 Authorization Code 발급, redirect_uri로 리다이렉트
인증에 성공하면 redirect_uri로 사용자를 리다이렉션시킨다.
나의 경우에는 backend의 /auth/google/callback 의 api 호출
이 때 다음과 같은 데이터를 함께 받는다. 구글 로그인의 경우 이 데이터는 query로 전송되었다.
Google Authorization Server로 부터 받은 데이터
code : Authorization Code // Access Token을 얻기 위해 발급하는 임시 코드이기 때문에 금방 사라짐
📚 7, 8, 9 Authorization Code와 Access Token 교환, Access Token 저장
Client는 Authorization Server에 5~6단계에서 발급받은 Authorization Code를 전달하고 Access Token을 응답받는다.
Access Token은 유출되면 안된다.
Google Auth Token Url
https://oauth2.googleapis.com/token
요청 예시
// Authorization Code와 Access Code 교환
const { data } = await axios({
method: "POST",
url: `${GOOGLE_AUTH_TOKEN_URL}`,
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
params: {
grant_type: "authorization_code", //고정 스트링
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_SECRET_ID,
redirectUri: GOOGLE_AUTH_REDIRECT_URL,
code: code, // Authorization Code
},
})
grant_type : 항상 authorization_code
code : 발급받은 Authorization Code
redirect_uri : Redirect URI
client_id : Client ID
client_secret : 발급된 Client Secret (유출되면 안됨)
응답 예시
{
access_token: "some token",
expires_in: 3599, //in seconds
scope: 'openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
token_type: 'Bearer',
id_token: "id token"
}
📚 10 접근 권한 생성 완료
이제 리소스(사용자의 email, name 등)에 접근할 수 있는 권한이 내 웹사이트에 인가되었다.
드디어 원하는 자원을 요청해서 사용할 수 있는 상태가 되었다.
📚 11, 12, 13, 14 Access Token 으로 리소스 접근
이 리소스의 접근 권한은 scope를 통해서 이루어진다.
1~2단계에서 요청한 scope에 대한 정보를 돌려준다.
나의 경우 킹받즈는 사용자의 이메일과 이름이 필요하여 이 두가지만 사용했다.
리소스 요청 예시
// 필요한 리소스 접근
const { data: resource } = await axios.get(
`https://www.googleapis.com/oauth2/v3/userinfo?access_token=${access_token}`
)
리소스 응답 예시
{
sub: 'some id',
name: '이해선',
given_name: '해선',
family_name: '이',
picture: 'https://lh3.googleusercontent.com/a/AEdFTp76UjYOvD-KVPovR2CM36wiz-y1UB2qtA4eDp5w=s96-c',
email: 'haesummy@gmail.com',
email_verified: true,
locale: 'ko'
}
📌 Authorization Code의 사용 이유
만약 직접 access token을 전달하게 되면 사용자에게 redirect시킬 때 access token 이 포함되어야 해서 사용자에게 브라우저를 통해 데이터가 유출되어버린다. 따라서 redirect 후 발급받은 authorization code로 backend에서 authorization server에 access token을 요청 후 backend에서 데이터를 처리하여 데이터가 유출되지 않도록 한다.
마치며
다음 글은 킹받즈에 Google OAuth를 사용하기 위한 선 작업(구글 클라우드 콘솔)과 실제 적용한 코드를 중심으로 포스팅을 해보려한다.
참고로 킹받즈는 React + Node.js + MongoDB로 이루어져있다.
Google에서 받아온 정보를 DB에 사용자 정보를 저장하는 것 까지 포스팅 예정이다.
사실 구현은 다 했는데 글을 더 쓰기는 졸려
redirect_url frontend로 빼서 api 요청 하는게 나을까? 직접 redirect_url을 backend 주소로 쓰는게 나을까?
url 생성도 변경 필요
'💛Backend' 카테고리의 다른 글
REST API에 대하여 (feat. 로이 필딩 논문) (1) | 2023.07.19 |
---|---|
Nest.js Passport 없이 로그인 Authorization Guard 만들기 (JWT Service) (0) | 2023.06.27 |
Nest.js에서 TypeORM 0.3 migtation 하기 (1) | 2023.06.25 |