My Boundary As Much As I Experienced

Next.js 14 애플 로그인 연동하기 (w. Firebase) 본문

FrontEnd/Next.js

Next.js 14 애플 로그인 연동하기 (w. Firebase)

Bumang 2024. 7. 10. 12:20

 

파이어베이스로 OAuth로 애플로그인을 구현하였다.

구글 로그인과 비슷할 줄 알았는데 훨씬 더 복잡한 인증서 발급 절차를 거쳐야 한다.

 

1. 파이어베이스 콘솔 - Authentication - 로그인 방법에서 제공업체 Apple을 추가한다.

 

2. 애플 디벨로퍼 페이지에 가서 인증서 ID 및 프로파일 - 인증서 (영문)을 클릭한다.

 

identifiers에서 app id, service id를 설정해준다.

이게 나름 쉽지 않다...

 

 

3. 파이어베이스로 돌아와 애플 상세보기에 인증서 정보들을 기입한다.

apple 팀 아이디, 키id, 비공개 키 들을 입력한다.

이것들 또한 애플 디벨로퍼 페이지에서 찾을 수 있다. 이것도 찾느라 고생 좀 했다.

 

 

4. Certificates, Identifiers & Profiles에서 Sign in With Apple을 활성화 후 configure창에 들어간다. 

 

 

configure창을 키고 아까 그 파이어베이스 콘솔에서 콜백 url을 복사하여 Website URLs에 추가한다.

 

이렇게 하면 파이어베이스 Oauth가 애플로그인을 탐지할 수 있다.

 

코드 상 구현

아래는 애플 로그인 컴포넌트이다.

disable에 로그인 되지 말아야할 조건들이 넣어져 있다.

<AppleLogin session={session} disable={!isOpened || !!authLoading || session === "none"} />

 

 

그리고 firebase OAuth의 signInWithApple을 사용하여 로그인하면 끝.

const AppleLogin = ({ session, disable, rest }: AppleLogin) => {
  const authLoading = useAuthStore((state) => state.authLoading);

  const loginWithApple = async (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();

    signInWithPopup(auth, provider)
      .then((result) => {
        const credential = OAuthProvider.credentialFromResult(result);
        const token = credential?.accessToken;

        const user = result.user;

        return { token, user };
      })
      .catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The credential that was used.
        const credential = OAuthProvider.credentialFromError(error);

        console.log("why?", errorCode, errorMessage);
        // ...
      });
  };

 

 

참고로 firebase의 onAuthStateChanged가 인증 정보의 변화를 탐지하여 콜백을 실행시켜주는데,

콜백에 전역변수로 user를 등록해주는 코드를 넣었고,

 

Redirect컴포넌트에서 로그인 시 유저 상황에 맞는 페이지로 리다이렉팅 해준다.

const useAuth = () => {
  const [setAuthLoading, setAuthFailed, setUser, logout] = useAuthStore((state) => [state.setAuthLoading, state.setAuthFailed, state.setUser, state.logout]);
  const openModal = useModalStore((state) => state.openModal);

  const handleChangeAuth = useCallback(async (user: FirebaseUser | null) => {
    try {
      setAuthLoading(true);
      if (!!user) {
        const { providerData } = user;

        const loginRes = await postLogin({
          platform: providerData[0].providerId,
          appId: providerData[0].uid,
          email: providerData[0].email || "",
        });

        if (loginRes) {
          loginRes.email = providerData[0].email || "";
        } else if (loginRes === null) {
          logout();
          await openModal(TooltipModal, {
            title: "Seems like you're\nNew to me",
            desc: "Please Sign up in ANTTIME APP",
            noDismiss: true,
            proceedLabel: "OK",
          });
        }

        setUser(loginRes);

        setAuthLoading(false);
        return;
      }
      setUser(null);
      logout();
      // eslint-disable-next-line
    } catch (e: unknown) {
      setAuthFailed();
      setAuthLoading(false);
      logout();
    }
    //eslint-disable-next-line
  }, []);

  useEffect(() => {
    // Firebase Auth 리스너
    // onAuthStateChanged는 상태변화를 감지하는 이벤트리스너면서, unsubscribe함수를 반환한다.
    // handleChangeAuth는 인증 상태가 바뀔 때마다 실행되는 훅이다.
    const unsubscribe = onAuthStateChanged(auth, handleChangeAuth);
    return () => {
      unsubscribe();
    };
    //eslint-disable-next-line
  }, []);
};

export default useAuth;