본격적으로, OAuth2 로그인을 구현하기 전에, OAuth가 무엇인지 알아보고자 합니다.
1. OAuth(Open Authorization)란?
OAuth의 사전적 정의는 다음과 같습니다.
OAuth는 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹 사이트 상의 자신들의 정보에 대해
웹 사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는
접근 위임을 위한 개방형 표준
쉽게 말하면, 어플리케이션을 이용할 때 사용자가 해당 어플리케이션에 ID, PW등의 정보를 제공하지 않고,
신뢰할 수 있는 외부 어플리케이션(Naver, Google, Kakao, Facebook 등)의 Open API에
ID, PW를 입력하여 해당 어플리케이션이 인증 과정을 처리해주는 방식입니다.
간단한 예시를 들면, 어플리케이션 로그인 시에 아래와 같은 로그인 화면을 많이 볼 수 있습니다.
어플리케이션 로그인 시에 해당 어플리케이션에 ID, PW를 포함한 여러 개인정보를 제공하지 않고,
Facebook, Google, Naver, Kakao 같이 신뢰할 수 있는 어플리케이션의 Open API와 통신하여
Facebook, Google, Naver, Kakao가 해당 사용자의 인증을 처리해주는 방식입니다.
이때, 위의 어플리케이션에서 일부 정보를 어플리케이션에 제공해줘서 해당 정보로 사용자를 관리하게 됩니다.
2. OAuth의 탄생 배경
OAuth이 없을 때의 상황을 생각해보자.
'A' 어플리케이션에서 Naver의 정보(리소스)를 가져오기 위해서는 Naver의 ID와 PW를 직접 입력받아서
'A' 어플리케이션에 저장해서 필요할 때마다 불러와서 사용을 해야했다.
이렇게 사용했을 때, '사용자' / 'A' 어플리케이션 / Naver 이렇게 3가지 입장에서 각각 문제가 발생합니다.
1. 사용자 : 'A' 어플리케이션에 Naver의 ID와 PW를 넘겨주는 것에 대해 신뢰할 수 없다.
2. 'A' 어플리케이션 : Naver의 ID와 PW를 저장하기 때문에 보안 문제가 생기는 경우 모든 책임을 져야한다.
3. Naver : 'A' 어플리케이션을 신뢰할 수 없다.
이 문제를 해결하기 위해 OAuth를 도입하여 인증을 외부 어플리케이션에 위임하여 처리하도록 해결합니다.
3. OAuth 2.0 용어 (구성 요소)
구분 | 설명 | |
Resource Server | OAuth2.0 서비스를 제공하고 Resource를 관리하는 서버 (ex - Google, Naver, Kakao, ...) 클라이언트(Client) - 이 서버로 인증 서버에서 발급받은 Token을 넘겨 개인 정보를 받을 수 있다. |
|
Resource Owner | 어플리케이션을 이용하려는 Resource Server의 계정을 소유하고 있는 사용자 | |
Client | Resource Server의 API를 사용하여 정보를 가져오려는 애플리케이션 서버 Client라는 이름이 붙은 이유는, Resource Server에 API를 요청하기 때문 |
|
Authorization Server | Clinet가 Resource Server의 서비스를 사용할 수 있게 인증하고, 토큰을 발행해주는 인증 서버 (ex - Google, Naver, Kakao, ... 의 인증 서버) 사용자(Resource Owner) -이 서버로 ID, PW를 넘겨서 Authorization Code 발급받음 클라이언트(Client) - 사용자가 발급받은 Authorization Code를 이 서버로 넘겨 Token 발급받음 |
|
AccessToken | JWT의 AccessToken - 해당 토큰으로 Resource Server에 요청해서 개인 정보를 받을 수 있다. |
|
RefreshToken | JWT의 RefreshToken - 해당 토큰으로 AccessToken을 재발급 받을 수 있다. |
4. OAuth 2.0 인증 과정
아래 이미지는 PAYCO의 OAuth 2.0 인증 과정입니다.
해당 이미지를 보면서 이해해봅시다!
* 사용자 - Resource Owner
* 서비스(사용자가 이용하려는 서비스) - Client
* PAYCO 인증 서비스 - Authorization Server
* PAYCO API 서비스 - Resource Server
이렇게 맵핑됩니다.
크게 요약해보면,
Client(사용자가 이용하려는 서비스)에서 Resource Owner(서비스를 이용하려는 사용자)를
대신하여 Authorization Server와 Resource Server에 요청을 보내 로그인을 수행한다.
자세하게 위의 인증 과정을 살펴봅시다.
1. 사용자가 서비스에게 서비스 접근 및 로그인 요청(소셜 로그인 버튼 클릭)
2. 서비스가 PAYCO 인증 서비스(Authorization Server)에 사용자 대신 로그인 요청
3. Authorization Server가 사용자에게 로그인 페이지 제공
4. 사용자가 ID, PW를 입력하여 Authorization Server에 요청하여 유효성 확인
5. 유효성이 확인되면, Authorization Server에서 사용자에게 Authorization Code 발급
6. 사용자가 서비스에게 Redirect Callback URL로 발급받은 Authorization Code를 담아서 요청
7. 서비스가 사용자가 전달한 Authorization Code를 사용하여 Authorization Server에 인증 요청(AccessToken 발급 요청)
8. Authorization Server에서 해당 Authorization Code를 검증 후 인증(AccessToken 발급) & 서비스에서 발급된 AccessToken 저장
9. 서비스에서 사용자의 인증 완료 & 로그인 성공 처리
10~13 : Resource Server로 발급받은 AccessToken을 사용하여 사용자의 해당 Resource(ID, 프로필 정보, ...)를 요청하여 응답받을 수 있다.
5. OAuth 2.0 인증 과정 예시(Naver 로그인)
더 자세히 알아보기 위해 실제 Naver 로그인 시 어떠한 과정을 거치는지 위의 이미지 순서대로 알아봅시다.
5-1. 어플리케이션 등록
우선, OAuth2.0 로그인을 사용하기 위해서는 이용하고자 하는 Resource Server에
자신의 서비스(어플리케이션)을 등록해야합니다.
네이버는 Naver Developers - Application에서 이 과정을 진행할 수 있습니다.
* Scope : 네이버(Resource Server)에서 사용하고자 하는 사용자의 정보
* 서비스 URL : 네이버(Resource Server)의 API를 사용하고자 하는 어플리케이션 URL
* 네이버 로그인 Callback URL : 로그인 성공 시 Authorized Code를 전달하는 URL(뒤에 파라미터로 전달)
이렇게 등록을 완료하면, 애플리케이션 정보로 Client ID와 Client Secret이 발행됩니다.
이렇게 애플리케이션 등록을 마치면, 해당 Resource Server에 요청을 보내 사용할 수 있습니다.
위에 사용된 용어를 다시 살펴봅시다.
(1) Scope
네이버(Resource Server) 내부에서 사전에 외부에 사용이 가능하도록 기능들을 정해둔 목록에서,
네이버 API를 사용하고자 하는 서비스에서 사용하고 싶은 기능만 골라서 사용할 수 있습니다.
이때, 서비스에서 사용하고 싶은 기능만 고른 목록을 Scope라고 합니다.
위의 이미지를 다시 보면, 네이버 로그인 API에서
'회원 이름', '이메일 주소', '프로필 사진'을 제공 정보로 선택하고 있는데,
이는 어플리케이션 구현 시 scope : name, email, profile_image 이런 형식으로 들어가게 됩니다.
이런 식으로, Resource Server에서 로그인 페이지 제공 후 로그인이 성공하면
사용자의 동의를 구하는 항목에 추가되게 됩니다.
(2) 서비스 URL
해당 네이버(Resource Server) 로그인을 사용하고자 하는 어플리케이션 서비스 URL이다.
내 경우에는 로컬에서 OAuth2 로그인을 테스트하는 용도이기 때문에 localhost:8080으로 설정했다.
말 그대로 프로젝트나 서비스의 도메인 URL을 입력하면 된다.
(3) Authorized redirect URIs
네이버(Resource Server)에서 서비스(Client)에게 Authorization Code를 전달하는 URL 통로이다.
(정확히는 Resource Server -> Resource Owner -> Resource Clinet로 전달)
또한, 해당 Redirect URI는 Client와 Resource Server 유효성 검사에서도 사용된다.
Resource Server에서 Redirect URI가 해당 Client의 URIs에 존재하지 않으면,
해당 Client가 아니라고 판단하여 인증에 실패한다.
(4) Client ID / Secret
* Client ID : 네이버(Resource Server)를 사용하고자 하는 서비스의 식별자 ID
네이버(Resource Server) 입장에서 다양한 서비스에 기능을 제공하는데,
서비스를 식별하는 지표가 된다.
* Client Secret : Client ID에 대한 PW로, 외부에 노출되면 안된다.
요약하면, Clinet ID / Secret은
네이버(Resource Server)의 기능을 사용하기 위한 ID / PW로 생각하면 됩니다.
5-2. 실제 사용자 로그인 인증 과정 예시
1. Resource Owner(사용자)는 서비스(Client)를 이용하기 위해 로그인 페이지로 이동한다.
서비스(Client)는 로그인 페이지를 제공하고, 이때 Resource Owner가
OAuth 2.0 로그인 (네이버 로그인, 카카오 로그인)을 눌러 로그인을 진행한다.
2. Resource Owner(사용자)가 OAuth 2.0 로그인을 누르면, Client(서비스)가
Authorization Server(인증 서버)에 로그인 요청을 보낸다.
네이버 로그인을 눌렀다고 가정한다.
http://localhost:8080/login/oauth2/code/google
로그인 요청 URL의 코드를 살펴봅시다.
https://nid.naver.com/oauth2.0/~ # 네이버 인증 서버 URL
&client_id=1 # Authorization Server에게 어떤 클라이언트인지 ID로 전달
&scope=name, email, profile_image # Resource Owner(사용자)가 사용하려는 기능, Clinet(내 서비스)가 사용하려고 하는 Resource Server(네이버)의 기능
&redirect_uri=http://localhost:8080/login/oauth2/code/naver # 개발자 센터에서 설정한 redirect URL
이후에 redirect_uri를 통해, Authorization Server(네이버 인증 서버)가
Client(내 서비스)에게 임시 비밀번호인 Authorization Code를 발급하여 제공합니다.
이때, 로그인 요청 URL의 서비스 정보(client_id, redirect_uri)와
개발자 센터에서 등록한 서비스 정보를 비교하여
등록된 서비스 정보와 일치할 때만 로그인 페이지를 제공합니다.
3. Naver의 Authorization Server(인증 서버)에서 로그인 페이지를 제공하고 ID/PW 입력을 요청한다.
4-1. Resource Owner(사용자)가 Naver의 ID/PW를 입력하고, 로그인 버튼을 누른다.
4-2. Resource Owner(사용자)가 입력한 ID/PW와
Authorization Server(네이버 인증 서버)에 등록된 ID/PW를 비교해서 일치 여부를 확인한다.
일치하면, Client(내 서비스)가 사용하려는 Resource Server(네이버 API 서버)의 Scope(기능)에
사용을 동의하는지, Resource Owner(사용자)의 동의를 요청하는 페이지를 제공한다.
Resource Owner(사용자)가 동의를 눌렀다는 것의 의미는,
Client(내 서비스)에 Resource Owenr(사용자)가
해당 기능 사용을 위임(delegation)했다는 것을 의미합니다.
따라서, 동의를 누르면 Client(내 서비스)에 Resource Owner(사용자)가
권한을 위임했다는 승인이 Authorization Server(네이버 인증 서버)에 전달됩니다.
이때, Authorization Server(네이버 인증 서버)가 가지는 정보는 다음과 같습니다.
1. Client id : Resource Owner(사용자)와 연결된 Client(내 서비스)가 누군지 식별하는 식별자
2. Client Secret : Resource Owner(사용자)와 연결된 Client(내 서비스)의 비밀번호
3. Redirect URL : Client(내 서비스)와 통신할 경로 URL (Client가 개발자 센터에서 설정한 Callback URL)
4. User id : Client(내 서비스)와 연결된 Resource Owner(사용자)의 id, 즉 내 서비스의 사용자의 유저 ID
5. Scope : Client(내 서비스)가 Resource Owner(사용자) 대신 사용할 Resource Server(네이버 API 서버)의 기능들
5. Resource Owner(사용자)가 Client(내 서비스)에 기능을 사용할 권한을 위임했더라도,
아직 Authorization Server(네이버 인증 서버)가 승인하지 않았으므로,
Authorization Server(네이버 인증 서버)가 Client(내 서비스)에게 권한 승인으로,
임시 비밀번호인 Authorization Code를 발급한다.
이때, Client(내 서비스)에게 바로 통신할 수 없고,
Resource Owner(사용자)에게 Authorization Code를 담은 redirect URL 경로를 전달한다.
6. Client(내 서비스)는 Resource Owner(사용자)가 전달한 Redirect URL을 받는다.
7. 전달받은 Redirect URL에서 Authorization Code를 받아서,
AccessToken 요청 URL에 Client Id, Client Secret, redirect URL 등 정보를 보낼 때
Authorization Code를 같이 요청보낸다.
8. Authorization Server(네이버 인증 서버)에서 7번에서 요청받은 URL에서 정보들을 비교하여,
Auhorization Server(네이버 인증 서버)에서 가진 정보와 일치한다면
AccessToken을 발급하여 Response에 담아 Client(내 서비스)에게 전달한다.
AccessToken을 발급했으므로, 필요없어진 Authorization Code는 지운다.
9. 토큰을 전달 받은 Client(내 서비스)는 Token을 내부에 저장하고,
Resource Owner(사용자)에게 인증 완료 및 로그인이 성공했다고 응답한다.
OAuth의 목적은 최종적으로 Authorization Server에게 AccessToken을 발급 받아서,
해당 AccessToken으로 Resource Server의 API를 이용하는 것입니다!
10~13. 이제 Client(내 서비스)는 Resource Owner가
Resource Server의 API가 필요한 서비스(Resource Owner의 ID, 프로필 등)를 요청할 때,
Client에서 Resource Server로 AccessToken을 담아 요청해서 API를 호출할 수 있으므로,
Resource Owner(사용자)의 ID, 프로필 정보 등 여러 정보를 Resource Server(네이버 API 서버)에서 받아서
Resource Owner(사용자)에게 서비스를 제공할 수 있다!
※ AccessToken 만료 시
위 과정에서 설명은 안 했지만, JWT와 동일하게
AccessToken이 만료되게 되면 RefreshToken을 통해 AccessToken을 재발급하여 사용합니다.
RefreshToken의 발급 여부와 방법, 갱신 주기는 Authorization Server마다 다릅니다.
보통은 Authorization Server에서 AccessToken 발급 시 RefreshToken도 함께 발급하고,
Client가 AccessToken, RefreshToken을 둘 다 저장해두고,
AccessToken을 사용하여 API 호출 시 AccessToken이 만료되어 401 에러가 발생하면,
Client가 RefreshToken을 Authorization Server에 보내서 새로운 AccessToken을 발급 받고
해당 AccessToken으로 Resource Server의 API를 호출하는 아래의 방식을 사용합니다.
📖 깃허브 링크 (전체 코드)
https://github.com/KSH-beginner/oauth2WithJwtLogin
📕 전체 로그인 구현 목차
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (1) - 회원(User) 관련 클래스 생성
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (2) - JWT란?
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (3) - JWT 관련 클래스 생성 / JWT 인증 로직
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (4) - 자체 JSON 로그인 커스텀하기
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (5) - OAuth란? / OAuth 2.0 인증 과정 예시
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (6) - OAuth 2.0 로그인 구현 사전 설정
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (7) - OAuth 2.0 로그인 관련 클래스 생성
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (8) - SecurityConfig 설정 클래스 생성
Spring Security + JWT를 이용한 자체 Login & OAuth2 Login API 구현 (9)- JWT 자체 로그인 & OAuth2 Login 테스트
Reference
https://doqtqu.tistory.com/295