일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 개발/Java
- 개발/MySQL
- ⌨️Developer
- 개발/언어론
- 알고리즘
- 대외활동/카카오테크캠퍼스
- 개발/컴퓨터네트워크
- 개발/Java/Spring
- electron
- AI/GPT
- 카테캠
- 개발
- ⌨️Developer/보안
- ai
- 개발/Tools/프레임워크/Spring
- 개발/보안
- 개발/Electron
- 개발/CS/OS
- 개발/프레임워크&라이브러리
- 개발/CS/알고리즘
- 개발/네트워크
- 취업
- 개발/webrtc
- 개발/언어/Java
- 카카오테크캠퍼스
- 개발/OOP
- 카카오 테크 캠퍼스
- 개발/에러
- AI/ML
- 개발/환경
- Today
- Total
봄수의 연구실
Goolge OAuth2 로그인 구현 with React 본문
Google Cloud Platform에서 OAuth 설정 먼저하자
구글 클라우드 콘솔에서는 OAuth 동의화면과 사용자 인증 정보를 등록해야 한다.
OAuth 동의화면
먼저 OAuth 동의화면에서는 앱 이름, 사용자 지원 이메일과 로고 등을 설정한다.
다음은 범위(scope)를 설정해야 한다. OAuth2를 사용하여 유저 정보에 접근 할텐데 어떤 정보에 접근 할지 알아야 한다. 추후 쿼리 날릴 때 파라미터로 날려야하므로 기억하자
마지막으로, 테스트 사용자에 자신이 사용할 email을 미리 등록한다. 팀원들이 있다면 팀원들도 등록해주자.
사용자 인증 정보
구글 클라우드 콘솔의 API 및 서비스 - 사용자 인증 정보 - OAuth2.0 클라이언트 ID에서 계정을 하나 생성해주자.
사용자 인증 정보에 등록하는 이유는 OAuth2 접근 할 때 client Id와 Redirect URI가 필요하다.
처음 클라이언트 ID를 선택하면, 클라이언트 종류를 고르는 메뉴가 나올텐데 자신이 개발하는 항목에 맞춰 골라주자
난 프론트니까 당연히 웹 애플리케이션으로 설정했다.
승인된 자바스크립트 원본에는 데이터를 요청하는 URI을 적어주자
Docs에 따르면 웹 애플리케이션을 호스팅하는 HTTP 원본이라, 이 값에는 와일드 카드나 경로를 포함하면 안된다. 80 외의 포트를 사용하는 경우 포트를 지정해주자.
예: https://example.com:8080
승인된 리디렉션 URI는 사용자 인증이 끝나면, 리다이렉팅 할 URI이다.
프론트 코드 처리
react-google-login 라이브러리를 쓰면 쉽게 구현 할 수 있었는데, Google에서 지원을 안할거란 이야기가 있어서 @react-oauth/google를 사용했다.(2023.03.31까지 마이그레이션 끝내라 공지도 하는데, 지금 시점으로 한 달 남은게 웃프다)
원래 계획은 클라이언트에서 token까지 모두 받는 것을 생각했는데, @react-oauth/google에선 클라이언트가 인증 코드만 처리하는 구조를 추천하기에 수정했다
최종 코드는 아래와 같다. 클라이언트에서는 인증 코드만 받아서, 이를 우리의 백엔드 서버로 보내 토큰을 돌려 받는 구조이다.
import { Box, Button } from "@mui/material";
import { useGoogleLogin } from "@react-oauth/google";
import axios from "axios";
const Login = () => {
const googleSocialLogin = useGoogleLogin({
scope: "email profile",
onSuccess: async ({ code }) => {
axios
.post("http://localhost:4000/auth/google/callback", { code })
.then(({ data }) => {
console.log(data);
});
},
onError: (errorResponse) => {
console.error(errorResponse);
},
flow: "auth-code",
});
return (
<Box>
<Box>
<Button onClick={googleSocialLogin}>Google Button</Button>
</Box>
</Box>
);
};
export default Login;
위의 코드에는 보이지 않지만, 라이브러리 사용전,provider로 감싸줘야 한다. 난 최상위인 main.tsx에 <GoogleOAuthProvider clientId={clientId}>
를 감싸줬다. 인자는 보다시피 client ID를 주면 된다.
scop에는 자신이 접근할 정보, onSuccess와 onError은 success/error 발생하면 실행할 함수를 기록한다.
flow: auth-code는 백엔드에서 refresh와 access token을 얻을 code를 얻기 위해 설정하였다
flow는 사용자 승인 작동 방식에 따라 갈리는데 자세한 것은 Authorization docs 를 읽어보자
받은 코드는 axios로 backend로 보내주자. post에 들어간 URI는 자신이 보낸 code를 처리할 api이다.
backend에서는 code를 token으로 교환하고, data로 던져준다.
onSuccess: async ({ code }) => {
axios
.post("http://localhost:4000/auth/google/callback", { code })
.then(({ data }) => {
console.log(data);
});
},
backend 처리도 살짝 살펴보자. google-auth-libray의 OAuth2Client를 client Id와 secret을 인자로 생성한다.
생선된 클라이언트에 code만 넣어주면, token 얻기 성공이다!
// front에서 넘어온 code를 정리합니다.
import {OAuth2Client} from "google-auth-library";
const oAuth2Client = new OAuth2Client(_google.clientId, _google.clientSecret, "postmessage");
fastify.post("/callback", async (req: FastifyRequest<{Body: {code: any}}>, res: FastifyReply) => {
const {tokens} = await oAuth2Client.getToken(req.body.code);
console.log("code ", tokens);
res.send(tokens);
});
}
🚨 OAuth2Client를 생성할 때, 3번 째 인자로 "postmessage"가 적혀 있을텐데, 절대 RedirectURI를 적으면 안된다.
google-auth-libray 최신 Docs를 보면, OAuth2Client로 redirect uri를 주는데, 그냥 postmessage로 두면 된다
Redirect uri를 주면, indirect uri 오류를 뱉는다. (docs를 좀 더 찾아봐야 할 듯)
여기까지 하면, token을 잘 받아오는 것을 확인 할 수 있다!
Error Report
idpiframe_initialization_failed
Error
브라우저의 캐시를 지워주자. 캐시를 지울 일이 개인적으로 구현하면서 많았는데, 정신 건강을 위해 시크릿 탭이나, PostMan을 사용하자
Origin is not allowed for the given client ID when using a GoogleLogin button
구글 클라우드 콘솔로 돌아가서, 리다이렉팅 URI과 승인된 자바스크립트 원본에 http://localhost
와 http://localhost:3000
을 적어주자
자신의 페이지가 열릴 URI와 포트를 적어주란 뜻이다!
느낀 점
- 어려운 문제일수록 stackoverflow나 다른 블로그를 보기 전에 docs를 읽는게 효과적이다
- 계속 라이브러리는 업데이트 되기 때문에, 잘못하면 에러의 늪에 빠진다
- BDD(블로그 주도 개발)이 내 성장에 크게 도움이 되지 않을 것이다
'DEV > Frontend' 카테고리의 다른 글
React state는 뭔가 (0) | 2023.02.08 |
---|---|
React Error Rendered more hooks than during the previous render (0) | 2023.02.08 |
리액트 에러 해결 Warning Each child in a list should have a unique key prop 에러 해결 (0) | 2023.01.13 |
React 왜 쓸까? (0) | 2023.01.12 |
Recoil 기초 (0) | 2023.01.12 |