🐽 모아모아는 자체적인 회원가입과 로그인 기능이 없고, 소셜로그인으로만 로그인이 가능하다. 회원가입의 장벽이 있을 것이라 생각해서 사용자 접근성 관점에서 소셜로그인으로 쉽게 모아모아 서비스를 사용하도록 결정했다.
소셜 로그인 구현 방법에는 여러가지가 있지만 모아모아 팀에서는 아래와 같이 구현하였다.
const loginUrl = `${process.env.REACT_APP_LOGIN_BASE_URL}/api/oauth2/authorization/${type}?redirect_uri=${process.env.REACT_APP_LOGIN_REDIRECT_URL}`; window.location.assign(loginUrl);
access token과 refresh token을 만들어 프론트 측에 보내기 - redirectaccess token과 refresh token을 받으면 로그인 성공했다고 판단하여 메인페이지로 redirect참고
localStorage vs Cookie
서버에서 발급해주는 JWT를 이용하여 사용자 정보를 조회할 수 있기 때문에 탈취당하지 않도록 클라이언트 측에서 잘 보관해야 한다.
XSS (Cross Site Scripting)
- 공격자가 악의적인 js 코드를 웹 브라우저에서 실행시키는 것
- 이 방법으로 브라우저에 저장된 중요 정보들을 탈취 가능하다.
CSRF (Cross Site Request Forgery)
- 정상적인 request를 가로채서 변조된 request를 보내 악의적인 동작을 수행하는 공격
XSS에 취약하다. CSRF 공격에는 안전하다.🐽 모아모아에서는 만료 시간이 30분인 access token을 localStorage에 저장하고, 상대적으로 만료시간이 긴 refresh token을 httpOnly옵션을 가진 cookie에 저장하기로 결정했다!!
Authorization header에 Bearer {access token} 형태로 넣는다.reissue 요청을 보낸다. 아니라면 api를 호출한다.Authorization header에 Bearer {access token} 형태로 넣어 api를 호출한다.export const setToken = async () => {
const token = localStorage.getItem(process.env.REACT_APP_TOKEN_KEY);
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
const expiredAt = new Date(
localStorage.getItem(process.env.REACT_APP_EXPIRED_AT_KEY),
);
const today = new Date();
const diffTime = expiredAt.getTime() - today.getTime();
if (diffTime <= 30000) {
const { data } = await axios.get(`${baseUrl}/reissue`, {
withCredentials: true,
});
today.setMinutes(today.getMinutes() + 30);
localStorage.setItem(process.env.REACT_APP_TOKEN_KEY, data.accessToken);
localStorage.setItem(process.env.REACT_APP_EXPIRED_AT_KEY, today);
axios.defaults.headers.common[
'Authorization'
] = `Bearer ${data.accessToken}`;
}
};
// 모든 api를 호출하기 전에 setToken 함수를 호출하여 실행해야 한다.
소셜로그인을 axios get 요청으로 처리했는데 아래와 같이 CORS 문제가 발생했다.

✨ 해결
소설 로그인 요청은 redirect_uri로 리다이렉트 되어야 해서 비동기 통신 방식으로 요청하면 안된다. 리다이렉트받을 수 있도록 브라우저 창의 url를 바꿔야 한다.
참고 : 소셜로그인 CORS 문제
백엔드 측 서버를 배포를 하고 프론트는 로컬에서 배포된 서버를 이용했다. redirect된 url에서 access token은 잘 받았는데 쿠키에 refresh token이 없는 상황이 계속 발생했다. 그 이유는 프론트와 백엔드 도메인이 일치해야 쿠키 전달이 가능하다.
✨ 해결
어떻게 해결할지 백엔드 분이랑 이야기를 많이 했다.
access token이 필요하고 access token 만료 시간이 지나면 refresh token이 필요했다.access token을 받으면 되지만, refresh token을 이용하여 access token을 재발급받는 api 테스트도 로컬에서 필요했다.CORS 관련 설정도 다 해주셨고 백엔드 서버에 변경사항이 생길 때마다 빌드 파일을 보내주셨다. 🙇♀️🙇♂️🙇♀️모아모아 백엔드 서버 로컬로 실행하기
- jar 파일 실행하기 (
java -jar {jar 파일 경로}.jar)Redis-x64-3.0.504.msi설치하기
http://localhost:8080로 api를 호출해야 하고, 배포된 사이트에서는 https://moamoadev.shop로 api를 호출해야 한다. 개발과 배포 상태에서의 백엔드 서버 url를 구분하기 위해 env 파일을 활용했다.📝 env 파일 활용하기
- 환경변수를 관리할 수 있고,
development과production여부에 따라 환경변수 값을 다르게 지정할 수 있다.CRA에서는 환경변수를 사용하기 위해서dotenv모듈이 설치되어 있으며, 루트 디렉토리에.env파일을 만드면 된다.- 환경변수명은 반드시
REACT_APP으로 시작해야 한다..env: 기본파일.env.development: 개발자 환경에서 로딩됨// .env.development REACT_APP_LOGIN_BASE_URL = http://localhost:8080 REACT_APP_LOGIN_REDIRECT_URL = http://localhost:3000/oauth/redirect REACT_APP_BACKEND_BASE_URL = http://localhost:8080 REACT_APP_TOKEN_KEY = TOKEN REACT_APP_EXPIRED_AT_KEY = EXPIRED_AT
.env.production: 배포 환경에서 로딩됨// .env.production REACT_APP_LOGIN_BASE_URL = https://moamoadev.shop REACT_APP_LOGIN_REDIRECT_URL = https://moamoadev.shop/oauth/redirect REACT_APP_TOKEN_KEY = TOKEN REACT_APP_EXPIRED_AT_KEY = EXPIRED_AT
로그인 기능을 구현하는 것이 백엔드와의 첫 협업 경험이었다. 소셜 로그인 기능을 함께 구현하면서 쿠키 이슈를 해결하는 것이 가장 어려웠다.😭 다른 도메인 간에 쿠키를 전달하는 방법이 있지만, 모아모아 팀은 백엔드 서버 관리하시는 분 덕분에 프론트가 로컬에서 CORS 문제 없이 백엔드 서버를 돌릴 수 있었고, 쿠키 전달 문제도 해결되었다. 백엔드 서버를 어떻게 실행하는지 친절히 알려주셔서 감사했다. 🙇♀️🙇♂️🙇♀️
소셜 로그인 기능을 구현하면서 새롭게 배운 것이 많았다.
그리고 .env 파일로 환경변수를 관리하는 방법을 알았지만, development와 production 여부에 따라 환경변수 값을 다르게 지정할 수 있는 방법을 새롭게 알게 되었다.
이제는 로그인 기능을 구현할 때 팀원들과 협의해야 하는 부분과 프론트가 어떤 역할을 해야 하는지 감을 잡았다!! 🙌