문제 상황
이메일로그인(JWT) + 소셜로그인(OAuth2.0 카카오) 2가지 방법으로 로그인기능을 구현하고 있었다.
이 과정에서 AccessToken(이하 AT), RefreshToken(이하 RT) 을 각각 세션스토리지와 쿠키에 저장하려고 했고, AT는 헤더를 통해 전달하기로 정했다.
이메일로그인은 헤더로 AT가 잘 넘어갔었기에, 카카오로그인도 같은 방식으로 하면 될줄알았다...
(하지만 이것때문에 3-4일 개고생 할줄은 몰랐지)
우리가 만들어둔 백엔드서버만 거치는게 아니라 카카오서버도 거쳐서 회원정보를 가져오고 로그인인증하는 과정이 추가되기 때문이다.
서비스 로그인에서 서비스 로그인 세션으로 이동할 때,
// OAuthLoginSuccessHandler.java
// 액세스 토큰은 헤더에 추가 -> 리다이렉트시 헤더에 있는 액세스토큰은 사라짐
response.setHeader("Authorization", "Bearer " + accessToken);
이렇게 헤더에 AT를 넣어서 전달해줬고, 이 과정에서 리다이렉트하면 헤더에 담아둔 access 토큰이 날아간다는 사실을 확인했다.
문제 원인
이전에 HTTP 관련 강의에서 설명했던 문장이 떠올랐다.
Http는 Stateless 하다
각각의 요청이 독립적이고 이전 요청과 완전히 분리되어있다는 것이다.
예를 들어 키오스크로 주문할 때
- Stateless: 매번 주문할 때마다 처음부터 다시 주문해야 함
- Stateful: 이전에 주문했던 내역을 기억하고 "저번과 같은 걸로 주세요"
이라는 것.
따라서, HTTP 리다이렉트(3xx 응답)가 발생하면, 브라우저는 자동으로 새로운 요청을 보내기 때문에 헤더에 담긴 AT는 전달되지 않은것이다.
추가 : 그럼 쿠키는 왜 유지됌?
쿠키는 브라우저가 자동으로 도메인에 맞춰 전송 하기 때문이다.
브라우저 ----[쿠키 설정]--> 서버
Set-Cookie: refreshToken=xyz789
브라우저 ----[리다이렉트]--> 새로운 URL
Cookie: refreshToken=xyz789 (자동 전송됨)
브라우저 ----[헤더 전송]--> 서버
Authorization: Bearer abc123
브라우저 ----[리다이렉트]--> 새로운 URL
(이전 헤더 정보 사라짐)
해결 방법
1. URL에 AT를 담아서 전달 (사용 지양)
인증인가가 빨리 해결되어야 다른 기능도 테스트할 수 있었기때문에 가장 간단한 방법으로 URL에 AT를 담아서 클라이언트로 보내고, URL에 담긴 AT를 session storgae에 저장하도록 했다.
이 방법은 정말 기능 구현만을 위해 사용한 방법으로 실제로 이렇게 진행되는 서비스는 엄청난 욕을 먹을거다.
왜냐하면, 이 토큰만 해석하면 토큰에 담긴 개인정보를 너무나 쉽게 알 수 있기 때문이다. (토큰탈취 권장서비스..)
만약 시간이 없다면 최소한 url로 통해 access token을 받아서 바로 session storage에 저장하고, url에서 토큰을 삭제하는 로직이라도 추가하길 바란다.
2. OTT 서비스
- AT는 헤더로 응답하고 싶었다. (자체 로그인(이메일 기반 로그인 서비스)과 동일한 서비스 로직을 구현하고 싶었기 때문에)
- 리다이렉트를 사용해야했다. (카카오 소셜로그인으로 인해)
- 쿠키는 setHTTPOnly가 설정되어 있다. (XSS(Cross-Site Scripting) 공격 방어)
위 3가지이유로 인해 AT를 쿠키에 담을 수 없었다. 그래서 생각난게 OTT.
- 리다이렉트시 URL에 토큰을 담는건 마찬가지지만, 임시 토큰이 담기기 때문에 기존 URL에 AT를 담았던 것과 다름
- 이번 프로젝트에서 redis를 사용해봐서 OTT도 redis에 담아봤다. 5분의 유효시간을 가진 토큰이므로 짧은 시간 임시적으로 저장하기 적합하다고 판단했다.
- OTT를 기반으로 토큰검증 과정을 한번 더 겨쳐서 AT를 URL이 아닌 sessionStorage에 저장하도록 했다.
느낀점
먼저 소셜로그인을 처음 구현해봤는데 별별 문제가 다 터졌다. 여기서 적은건 "리다이렉트시 access token이 소실된다" 이거지만,
이로 인해 로그인을 해도 로그인이 안됐다고 구분되어서 로그인 후 사용할 수 있는 서비스가 진행되지 않았다.(매우매우 큰 문제)
또한 HTTP의 stateless 는 달달 외울 정도로 알고 있던 내용이었는데 이 당연한걸 직접 서비스를 만들 때는 활용하지 못했다. 이를 계기로 강의반복과 한발짝 멀어진 느낌...
인증인가의 중요도를 느낌과 동시에 프로젝트를 통해 몸소 부딪혀보는게 더 효과적이라는 것을 느꼈다.
'하고싶은거 > 삽질' 카테고리의 다른 글
구글에 블로그 노출하기2 (색인 생성 요청 거부, 실시간 테스트 문제 감지) (1) | 2024.06.26 |
---|---|
이클립스 로고 깜박임, java was started but returned exit code=1 (1) | 2024.06.14 |
! [rejected] master -> master (fetch first) git push 에러 (0) | 2024.05.09 |
문자 char 입력시 오류 : invalid conversion from ‘const char*’ to ‘char’ [-fpermissive] (0) | 2024.04.17 |
min 함수 오류 : required from here (0) | 2024.04.05 |
#개발 #게임 #일상
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!