인프런 커뮤니티 질문&답변

이우열님의 프로필 이미지

작성한 질문수

Next + React Query로 SNS 서비스 만들기

spring boot를 사용한 social login

해결된 질문

24.05.27 17:15 작성

·

294

0

Next.js와 Spring boot를 사용해서 소셜 로그인을 추가하려고 합니다.

소셜 로그인의 경우 코드와 토큰을 프론트에서 관리하지 않는 것이 좋다고 하여 백엔드에서 모든 로직을 처리하고 있습니다.

 

현재 프론트에서 window.location.href = "http://localhost:8080/oauth2/authorization/google";

위와 같은 경로로 백엔드로 소셜 로그인 요청을 보내고

 

백엔드에서는 소셜 로그인을 진행한 뒤에 유저 정보를 생성하고 JWT를 생성한 뒤 응답의 헤더에 쿠키 형태로 JWT를 넣어 response.sendRedirect("http://localhost:3000/auth/social");로 리다이렉트하고 있습니다.

 

프론트에서는 /auth/social 페이지에서 쿠키에 있는 JWT를 꺼내 유저 정보를 가져오는 API를 다시 호출해 유저 정보를 가져오고 있습니다.

이 후 auth.js 라이브러리를 통한 session 관리를 하고자 하는데 session을 업데이트 하려면 어떻게 해야 하나요..?

(session.user가 있는지 없는지를 통한 로그인 체크를 위해 사용한다고 이해했습니다.)

 

서버 컴포넌트에서 import { auth } from "@/auth"; 를 통해 가져온 session에 데이터를 넣어보았지만 데이터가 제대로 들어가지 않는 것 같아 조언을 구해봅니다..

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

2024. 05. 27. 17:21

조금 복잡하긴 한데 POST /api/auth/session을 하시면 됩니다. csrfToken을 넣으셔야 할 수 있습니다. 다음 댓글 참고하세요. 서버컴포넌트라는 가정 하에 진행됩니다.

https://github.com/nextauthjs/next-auth/discussions/9715#discussioncomment-9225447

이우열님의 프로필 이미지
이우열
질문자

2024. 05. 27. 18:28

if (csrfToken) {
  fetch("/api/auth/session", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      cookies: `authjs.csrf-token=${csrfToken}`,
    },
    body: JSON.stringify({
      csrfToken: csrfToken?.split("|")[0],
      user: {
        ...user,
      },
    }),
  });
} 

csrfToken을 추출해서 위의 링크 예시대로 요청을 보내봤습니다.

근데 jwt 콜백 함수로 넘어가지 않는 것 같네요...

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

2024. 05. 27. 23:06

지금 callbacks.jwt나 callbacks.session이 있는 상황이신가요? 지금 jwt가 아니라 session 쪽이 호출되고있는지도 모르겠습니다.

https://authjs.dev/reference/nextjs#unstable_update

이렇게 signOut같은 것 불러오는 것처럼 unstable_update를 불러서 세션 업데이트 하는 함수도 있네요.

이우열님의 프로필 이미지
이우열
질문자

2024. 05. 29. 11:06

최대한 시도를 해봤는데 로직을 변경해야 할 것 같습니다..ㅎㅎ
스프링과 협업할 당시 동일 window.location.href = "http://localhost:8080/oauth2/authorization/google"; API 주소로 하이퍼링크 요청을 보내면

auth.js에서 세션에 유저 정보를 등록하고자 하는데 이 때 어떤 방식으로 해야 할까요..

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

2024. 05. 29. 12:21

일단 oauth의 핵심은 구글이 redirect url로 요청을 쏴준다는 것이고, 그 url에서 다시 POST /api/auth/session을 호출하셔서 세션 등록을 해야합니다.

이우열님의 프로필 이미지
이우열
질문자

2024. 05. 29. 15:28

import { cookies } from "next/headers";
import { getUserInfo } from "./c/getUserInfo";
import { auth } from "@/auth";
import { redirect } from "next/navigation";

export default async function SocialRedirectPage() {
  const cookieStore = cookies();
  const accessToken = cookieStore.get("AccessToken")?.value!;
  const refreshToken = cookieStore.get("RefreshToken")?.value!;
  const csrfToken = cookieStore.get("authjs.csrf-token")?.value!;
  const pk = cookieStore.get("Pk")?.value!;

  const session = await auth();

  // console.log({ accessToken, refreshToken, csrfToken });

  const user = await getUserInfo(accessToken, pk);

  // console.log({ user });

  if (csrfToken) {
    const response = await fetch(
      `${process.env.NEXTAUTH_URL}/api/auth/session`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Cookie: `authjs.csrf-token=${csrfToken}`,
        },
        body: JSON.stringify({
          csrfToken: csrfToken?.split("|")[0],
          user: {
            name: user.nickname,
            email: user.email,
            image: user.profileImage,
          },
        }),
      }
    );

    // console.log({ response });
  }

  // console.log({ session });

  // redirect("/auth/social/c");

  return <div>Redirecting...</div>;
}

이런 식으로 짜봤습니다.
콜백으로 jwt, session 둘 다 사용하고 있어서 체크해보았지만 post 요청을 보내도 콜백 함수에는 찍히는게 없네요

response로 찍어본 post 요청에는 200으로 성공 코드가 돌아오긴 합니다..

콘솔에 user도 잘 나오는데 session을 찍어보면 null이라고만 뜨네요..

이우열님의 프로필 이미지
이우열
질문자

2024. 05. 30. 10:00

며칠 간의 고생 끝에 해결했습니다..

auth.js의 구조 자체가 로그인이 인증되지 않으면 세션 값이 없으며 접근 또한 불가능하게 되어있다고 하네요..

소셜 로그인의 경우 Credentials를 통해 인증이 되지 않아 세션 데이터를 업데이트든 뭐든 할 수 없는 상황이었습니다.

 

제 해결 방법은 기존 아이디와 패스워드를 입력하고 진행되는 로그인 방식을 살리면서 소셜 로그인을 추가하는 방법이었기 때문에 분리가 필요했습니다.

 

클라이언트 요청

"use client";

import { signIn, useSession } from "next-auth/react";

signIn("social-login", { redirect: false, accessToken, refreshToken, pk })

 

src/auth.ts

// 기존 아이디 비밀번호 입력 로그인
Credentials({
  id: "default-login",
  name: "DefaultLogin",
  credentials: {
    userIdOrEmail: {},
    password: {},
  },
  ...
})

// 소셜 로그인
Credentials({
  id: "social-login",
  name: "SocialLogin",
  credentials: {
    accessToken: { label: "Access Token", type: "text" },
    refreshToken: { label: "Refresh Token", type: "text" },
    pk: { label: "User PK", type: "text" },
  },
  ...
})

이렇게 Credentials에 id를 부여하여 signIn을 진행했습니다.

이렇게 하니 const { status } = useSession(); 로 출력된 status가 unauthenticated에서 정상적으로 authenticated로 변경되는 것을 확인할 수 있었습니다.

로그인이 된 상태기 때문에 session에 접근해서 데이터도 확인할 수 있었습니다!!

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

2024. 05. 30. 13:46

흐어 고생하셨습니다. 분명 세션이 바뀌어야하는데 왜 안 되나 했더니 기존에 세션이 존재하지 않아서였군요.