백엔드의 소셜 로그인 : 앱, 웹과의 소통은 어떻게 할까

조오닭·2024년 2월 29일
3

생각보다 간단한 이야기인데 자료가 많지 않아서 내용 파악에 있어 굉장히 오래 걸린 주제다.
스스로 내용 정리 겸 다들 헤매지 않았으면 좋겠어서 이 벨로그를 작성!

나는 현재 앱, 웹 서비스의 백엔드를 개발하고 있다. 사실 프론트엔드를 딥하게 해본 적이 없어 웹과 앱 그냥 언어나 라이브러리만 조금 다르고 백엔드와 REST 소통을 할 때 비슷한 줄 알았는데...

소셜 로그인(OAuth2)를 구현할 때 감이 잡히질 않았다.

가뜩이나 django는 자료가 많이 없기에... 그래서 레퍼런스가 많은 스프링으로 그나마 감을 잡으려 했다.
사실 웹 프론트엔드와의 소통은 정말 자료가 많다. 그만큼 방법도 많았다.
3일 전의 나는 앱, 웹의 소셜 로그인 방식이 같은 줄 알았기에 그냥 바로 방법을 정리해서 FE분들과 상의하였다.
하지만...

앱 fe 개발자 : 어? 저는 uid, 소셜 종류만 던졌어요!

하나도 모르면 아무 소린지 모르겠지만, 웹 oauth 방식을 알면 도파민이 쏟아지는 말이다.

바로 구글링으로 백엔드-앱의 소셜 로그인이 어떻게 이루어지는지 확인했고, 정말 자료가 1도 없어 막막했다.
그나마 카카오 데브톡에 의지했다. (데브톡 짱)

아무튼 서론이 좀 길었는데, 이 게시글에선 간략한 oauth2.0 방식과 앱/웹의 소셜로그인 처리 차이를 설명하겠다.


OAuth2.0 동작 방식

사실 oauth2.0은 구글에 검색만 해도 많이 나오니, 그 글을 통해 조금 더 알아보는 것을 추천한다.
어떻게 동작하는지 조오금 복잡한데 아주 간단히 설명하자면,

  1. 각 소셜의 developer 페이지에서 OAuth2.0 id와 secret key를 발급받는다. (단, 카카오는 조금 다르다.)
  2. 인가 코드(Authorization code)를 받기 위해 redirect uri(callback uri)로 필요한 정보를 보낸다.
  3. Access token을 받기 위해, 소셜의 token request uri로 2번의 인가 코드를 보낸다.
  4. 사용자의 정보를 받기 위해, 소셜의 user info uri로 3번의 access token을 보낸다.
  5. 4번에서 받은 사용자의 정보는 DB에 저장하고, access token과 인가코드로 로그인을 완료한다.

간단하게 축약시킨 것이 이것이다^^
중요 단어만 뽑아내자면,

redirect(callback) -> 인가코드 -> access token -> user info -> DB 저장 및 로그인 완료

이 절차로 진행된다.


웹 FE와는 어떻게 통신해야 할까?

OAuth2.0 동작 방식은 알겠는데... 어디까지가 fe고 어디까지가 be지?...?

안타깝게도 OAuth2.0는 프론트엔드와 백엔드의 경계가 모호하다.
따라서 구현 방식이 사람마다 다를 수 밖에 없는데 수많은 티스토리, 벨로그, 깃허브를 본 결과 총 네 가지로 축약할 수 있다.

1. Access token을 웹 프론트엔드(FE)에서 담당한 경우

위의 동작 방식 중 웹 FE가 3번까지 수행하는 경우다.

웹 FE : redirect(callback) -> 인가코드 -> access token (-> user info)
BE : (user info ->) DB 저장 및 로그인 완료

즉, 웹 FE가 access token을 발급하여 BE에게 access token(가끔 4번의 사용자의 정보도 보내는 경우도 있었음)을 전송하고, BE는 로그인만 처리하는 흐름이다.

BE인 나는 개이득이겠지만^^ 소셜의 access token을 서로 왔다갔다해서는 탈취 당하면... 서비스가 문 닫을 수도 있다.

2. Access token을 백엔드(BE)에서 담당한 경우

위의 동작 방식 중 웹 FE가 2번까지 수행하는 경우다.

웹 FE : redirect(callback) -> 인가코드
BE : access token -> DB 저장 및 로그인 완료

즉, 웹 FE가 redirect까지 담당하고, access token과 사용자 정보를 불러와 저장하는 것은 BE의 역할이다.
가장 정석적이고 흐름이 깔끔하다는게 특징이다. 보안 이슈도 딱히 없는 걸로 안다.

3. 백엔드(BE)가 모든 API를 만들어 웹 프론트엔드(FE)가 사용하는 경우

모든 동작을 BE가 api로 구현하고, 웹 FE가 사용자에게 uri로 중개만 하는 경우다.
즉, BE에서 소셜 로그인 페이지, token 얻기, 사용자 정보 얻기를 모두 api로 구현하면 웹 FE가 사용자에게 api를 뿌린다.

이 경우에는 redirect uri가 어디에 위치하냐에 따라 또 다시 나뉜다.

1) 웹 FE에 위치

redirect uri가 웹 FE에 위치해 있으면, 웹 FE와 BE의 흐름은 다음과 같다.

소셜 로그인 페이지 api(BE) -> redirect uri(웹 FE) -> 인가 코드 받아서 전송 (웹 FE) -> 
Access token과 사용자 정보 얻기(BE) -> 로그인 완료(BE)

이 또한 2번과 동일하게 많이 사용하는 방법이다. 단점이라면 백엔드를 두 번 호출하는거,,,?

2) BE에 위치

redirect uri가 BE에 위치해 있으면, FE에선 사용자에게 최초 페이지만 백엔드로 넘기고 그 후 모든 동작을 BE가 처리한다.

흐름이 깔끔하지만, 추후에 웹FE가 싫어하는 CORS 오류가 발생할 수 있다는 점이 특징이다.

결론?

2번과 3-1번 중에 선택하면 된다. 나는 2번을 선택하기로 했다.


앱 FE와는 어떻게 통신할까?

자료가 정말 없지만 없는 만큼 간단해서 어이가 없었다.
왜 앱 FE는 uid와 소셜 종류만 BE에게 전달했다고 했을까?

1. 앱에서 로그인 창을 웹뷰로 띄우는 방식

어플 내에서 동작하되 웹뷰로 띄워 새 창에서 로그인 창을 띄우는 방식이다.
이 경우, BE 입장에선 웹FE와 같이 동작하며, 외부 패키지를 설치하여 redirect을 처리한다.
BE는 앱용 로그인을 따로 구현할 필요가 없어 매우 좋은 방식이지만...

하지만 UX 측면에서 너무 극혐이다.
앱에서 소셜로그인을 하려 하는데, 카카오톡 어플이 아닌 카카오 웹 페이지가 나타났다고 생각한다면... 으악

따라서 대부분 2번을 선택한다고 한다.

2. 앱에서 소셜 앱으로 연동하는 방식 (네이티브)

사용자의 핸드폰 내 소셜 어플을 통해 인증하다보니 사뭇 다르다.
사실 조금만 생각해보면 로그인을 웹에서가 아닌 앱으로 연동하는 것이므로 동작 처리가 다를만하다.

이 경우에는 앱 FE와 BE의 흐름은 다음과 같다.

소셜 앱으로 이동(앱FE) -> 인증 완료(앱FE) -> uid, 사용자 정보 처리(BE)

즉, 인가 코드와 access token은 앱 FE에서 한 번에 처리된다.
이 때 앱 FE에선 돌아오는 값이 uid, 이메일 등과 같은 사용자 정보만 돌아오고, 이 정보를 소셜 종류와 함께 BE에게 요청해 사용자 정보를 저장하는 것이다.

따라서 BE에서 할 일은 소셜 종류, uid를 기준으로 사용자 정보만 저장하면 된다. 로그인도 소셜 어플에서 자체 처리한다.

여담으로 사용자의 핸드폰에서 진행되기 때문에 탈취될 가능성이 웹보다 현저히 적다고 한다.
(핸드폰 자체를 탈취하지 않는 이상 로그인 과정이 웹 상으로 노출되는 것이 아니기 때문이다.)

끝.
정말 끝이에요.

profile
백엔드 응애

0개의 댓글

관련 채용 정보