A complete log of the innumerable errors I met today.
client/src/pages/SignIn.jsx
export default function SignIn() {
const REST_API_KEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const REDIRECT_URI = "http://localhost:3000/oauth/kakao";
const KAKAO_LOGIN_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;
const socialLoginHandler = () => {
window.location.assign(KAKAO_LOGIN_URL);
};
return (
<button onClick={socialLoginHandler}>Login with Kakao</button>
)
}
위 코드는 Login with Kakao 버튼을 눌렀을 때, KAKAO_LOGIN_URL로 연결해주는 로직이다.
const code = new URL(window.location.href).searchParams.get("code");
console.log(code);
const getuserInfo = (code) => {
const userInfo = axios.get(`http://localhost:80/oauth/kakao/callback?code=${code}`, { authorizationCode: code });
};
이걸 Oauth에서 사용하려 한다.
처음에는, 위 코드가 KAKAO_LOGIN_URL 에서 진행되어야 하기 때문에
SignIn.jsx에서 넣어야 할지, Oauth.jsx라는 페이지 하나를 생성해 써야 하는지 헷갈렸다.
두번째 방법이 맞는 것 같았지만, 그 경우엔 페이지를 새로 생성해야 하는데 App.js에 path를 어떻게 해야할지 모르겠어서 고민을 많이 했다.
KAKAO_LOGIN_URL 주소가 http://localhost:3000 으로 시작하는게 아니라 https://kauth.kakao.com/oauth~~ 이기 때문에 path들을 모아놓은 App.js에서 연결을 할 수 없어 보였다.
몇시간동안 고민한 결과(🥲), 내가 KAKAO_LOGIN_URL 페이지가 어떤 페이지인지 잘못 이해하고 있었음을 알아내었다.
위 Logging In... 화면이 띄워질 동안 다음의 로직이 진행된다.
1. 클라이언트가 인가코드를 카카오에게 요청하여 받아오고
2. 서버에 넘겨주고
3. 그 인가코드로 서버 oauth.js에서는 카카오에 엑세스토큰을 받아오고
4. https://kapi.kakao.com/v2/user/me 로 userInfo를 카카오에게 요청하고 받아와 클라이언트에게 보내준다.
client/src/pages/Oauth.jsx파일을 생성하여, 다음 로직을 집어넣고 (로직만 참고),
const code = new URL(window.location.href).searchParams.get("code");
console.log(code);
const getuserInfo = (code) => {
const userInfo = axios.get(`http://localhost:80/oauth/kakao/callback?code=${code}`, { authorizationCode: code });
};
App.js에서 <Route path="/oauth/kakao" element={<Oauth />} />
를 추가해주면 Logging In... 뜨는 화면이 주소가 있는 page이므로 파일에 추가해주고 Oauth.jsx내에서 코드를 짜면 된다.
(Redux-toolkit)
function Oauth() {
const code = new URL(window.location.href).searchParams.get("code");
const navigate = useNavigate();
const dispatch = useDispatch();
const userInfo = useSelector((state) => state.user);
useEffect(async () => {
await axios
.post(`http://localhost:80/oauth/kakao?code=${code}`)
.then((data) => {
console.log(data);
console.log("서버에서 주는 유저인포", data.data.data.userInfo);
dispatch(setUserInfo(data.data.data.userInfo));
//const userLocalInfo = JSON.stringify(data.userInfo);
//localStorage.setItem("userLocalInfo", userLocalInfo);
//First Project에서는 위 코드처럼 유저정보를 Redux로 local에 저장했지만, 이 경우에 새로고침을 했을 때 정보가 날아가서 이번에는 그렇게 하지 말고 accessToken으로 처리를 시도해보려 한다.
navigate("/");
})
.catch((err) => console.log(err));
}, []);
return (
<>
{userInfo.id ? (
<Navigate to="/" />
) : (
<div className="flex justify-center items-center text-ducks-gray-666 font-poppins text-18 m-90 h-18 w-18">
Logging In...
</div>
)}
</>
);
}
server에서는 상관 없지만, client에서는 .env파일 내 변수 앞에 꼭 REACT_APP_
을 붙여줘야 한다.
client파일에선 `${process.env.REACT_APP_KAKAO_CLIENT_ID}`
이렇게 갖다 쓰인다.
어떻게 알았냐구요?
이 에러를 만나고 알게 되었답니다 🥶
(화면의 해결방안을 클릭하면 여기로 이동한다. 추후 발생한 문제들도 여기서 1차적인 원인을 파악하고, 2차적으로는 구글링과 직접 에러핸들링을 통해 해결했다.)
선택항목 설정을 했음에도, 서버 터미널에서 유저의 email 정보가 카카오로부터 받아와지지 않는 에러도 있었다.
구글링으로 KAKAO_LOGIN_URL 뒤에 &scope=account_email
을 붙여야 한다는 걸 알게 되었다.
즉,
const KAKAO_LOGIN_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_KAKAO_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_KAKAO_REDIRECT_URI}&response_type=code&scope=account_email`;
처음엔 작동했다. 그러나 계속해서 웹 콘솔에 500 에러, 서버 터미널에서는 400 에러, Redirect URI Mismatch 에러 등 수많은 에러가 났다.
단순 typo 문제도 있었고, .env파일 설정문제도 있었으며, 카카오에서 받아온 유저정보(kakaoUserInfo) 안에(kakaoUserInfo.data.kakao_account로 접근) email과 profile 정보가 있다는 걸 서버 터미널에서 계속 확인하면서 해결했고, 또 클라이언트에서 data.data.data.userInfo로 유저정보를 받는다는 것도 계속 콘솔 찍어보며 깨닫는 데 시간이 많이 소요되었다.
결론적으로는 다음과 같은 코드를 사용했을 때 잘 작동했다.
const KAKAO_LOGIN_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_KAKAO_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_KAKAO_REDIRECT_URI}&response_type=code`
🍟 server에서 node index.js로 서버 켜고 나서 웹페이지 실행시키면, server terminal 에 참 많은 정보가 찍힌다. (물론 server파일에 console.log(콘솔에찍힐정보)이라고 써놔야 찍힌다.) 여기서 보이는 정보와 에러설명을 찬찬히 읽어보고 구글링 하면 해답이 보인다는 걸 깨달았다.
카카오 로그인 화면과 동의화면을 보면서 에러 해결을 하고 싶었는데, 한번 카카오 로그인 했더니 계속 정보가 저장이 되는지, 바로 로그인이 된 상태로 http://localhost:3000 에서 떴다.
그래서 시원하게
' Chrome 설정 -> 보안 및 개인정보 보호 -> 인터넷 사용 기록 삭제 -> 고급 ' 에서 기록을 싹 다 지우고 Chrome 종료 후 다시 시작해봤다.
해결된 줄 알았지만, 카카오 로그인화면까진 뜨는데, 동의화면이 떴다 안떴다 했다. 시크릿 모드로 로그인하고 일반 모드로 로그인하길 반복했지만 그것도 처음 한번만 먹혔다.
처음에는 useEffect를 사용하지 않고 다음과 같이 코드를 짰기 때문에 일어난 현상이었다.
axios
.post(`http://localhost:8080/oauth/kakao/callback?code=${code}`)
.then((data) => {
dispatch(setUserInfo(data.data.data.userInfo));
navigate("/");
})
.catch((err) => console.log(err));
이걸 다음과 같이 고쳤더니 해결이 되었다. ( + async, await 비동기 처리해주니 내가 원하는 순서대로 (vscode상 순서대로) 개발자 콘솔에 찍혀서 아름다웠다. )
useEffect(async () => {
await axios
.post(`http://localhost:80/oauth/kakao?code=${code}`)
.then((data) => {
dispatch(setUserInfo(data.data.data.userInfo));
navigate("/");
})
.catch((err) => console.log(err));
}, []);
아직 디자인은 미완성이다. 😅
짜잔 정보가 잘 받아와진다.