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

챠챠_님의 프로필 이미지
챠챠_

작성한 질문수

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

Static(SSG) 모드와 사라진 ISR 모드

배포테스트할때 클라이언트에서 api호출하면 쿠키가 전달되지 않고있습니다.

해결된 질문

작성

·

578

·

수정됨

0

안녕하세요 선생님

배포테스트할때 클라이언트에서 api호출하면 쿠키가 전달되지 않고있습니다.

 

클라이언트에서는

credentials: 'include'를 적용했고

const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/user/setting`, {
        method: 'PATCH',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(userSettingObj),
      });
      if (response.ok) {
        const sessionUpdateInfo = await response.json();
        await updateSession(sessionUpdateInfo);
        router.push('/');
      }

 

서버에서는

const express = require('express');
const cors = require('cors');
const passport = require('passport');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const morgan = require('morgan');
const path = require('path');
const hpp = require('hpp');
const helmet = require('helmet');

const postRouter = require('./routes/post');
const postsRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const usersRouter = require('./routes/users');
const db = require('./models');
const passportConfig = require('./passport');

dotenv.config();
const app = express();
db.sequelize.sync()
  .then(() => { console.log('db 연결 성공') })
  .catch(console.error);
passportConfig();

if (process.env.NODE_ENV === 'production') {
  app.use(morgan('combined'));
  app.use(hpp());
  app.use(helmet());
} else {
  app.use(morgan('dev'));
}

app.use(
  cors({
    origin: ['http://localhost:3000', 'whatisyourmbti.com', 'http://43.201.56.221'], // true or * // access-control-allow-origin가 true된다. --> 다른 도메인끼리 api 요청
    credentials: true, // access-control-allow-credential가 true된다. --> 다른 도메인끼리 쿠키 전달
    method: '*',
  })
);
// 프론트에서 보낸 정보를 req.body에 넣어준다. 순서 중요!
app.use(express.json()); // json 형식으로 보냈을때 데이터 처리해줌
app.use(express.urlencoded({ extended: true })); // form submit으로 보냈을 때 데이터 처리해줌
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
  saveUninitialized: false,
  resave: false,
  secret: process.env.COOKIE_SECRET,
  cookie: {
    httpOnly: true,
    secure: false,
  }
}));
app.use(passport.initialize());
app.use(passport.session());

app.use((req, res, next) => {
  console.log('Session ID:', req.sessionID);
  console.log('Cookies:', req.cookies);
  console.log('Signed Cookies:', req.signedCookies);
  next();
});

app.get('/', (req, res) => {
  res.send('hello express');
});

app.get('/api', (req, res) => {
  res.send('hello api');
});

app.use('/post', postRouter);
app.use('/posts', postsRouter);
app.use('/user', userRouter);
app.use('/users', usersRouter);

app.listen(80, () => {
  console.log('서버 실행 중!');
});

credentials: true, 쿠키옵션을 설정해주었는데

0|app | Session ID:---------------------------- U8DRuillNv2DBRmexmO1mZZ7fGJeWXCw

0|app | Cookies:------------------------------- [Object: null prototype] {}

0|app | Signed Cookies:------------------------ [Object: null prototype] {}
이런식으로 쿠키값이 전달되고 있지 않아서

유저 정보가 필요한(로그인 확인)로직에서 401에러가 떨어지게 됩니다.

app.use(session({
  saveUninitialized: false,
  resave: false,
  secret: process.env.COOKIE_SECRET,
  cookie: {
    httpOnly: true,
    secure: false,
  }
}));

위부분들을 검색해보고 바꿔보기도 했는데, 잘안되더라구요.

클라이언트의 ip는 http://43.201.56.221입니다.

 

쿠키는 로그인 후 프론트서버에서 브라우저에 삽입해주고 있습니다.

console.log(`${process.env.NEXT_PUBLIC_BASE_URL}/user/login ---------------------login api`);
          const authResponse = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/user/login`, 
            {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                ...credentials
              }),
            }
          );
          
          // 프론트서버에서 백엔드서버의 로그인 토큰을 받아온것. 토큰은 문자열이라서
          // cookie라이브러리로 객체로 만들어준다.
          let setCookie = authResponse.headers.get('Set-Cookie');

          console.log('set-cookie', setCookie);
          if (setCookie) {
            const parsed = cookie.parse(setCookie);
            console.log(parsed, '---------------parsed cookie');
            // 브론트서버에서 브라우저에 쿠키를 심어준다.
            // 프론트서버에 쿠키를 심으면 안된다! 왜냐하면 프론트서버는 서버라서 공용이다.
            // 여러 브라우저가 전부 프론트서버르 바라본다. 개인정보 유출 문제 발생할 수 있다.
            cookies().set('connect.sid', parsed['connect.sid'], parsed); // parsed = 나머지 옵션들
          }
          
          console.log(authResponse, '--------------------------------authResponse');
          let user = await authResponse.json();
          console.log(user, '--------------------------------user'); 
          // console.lo(authResponse);
          if (!authResponse.ok) {
            return null;
          }

          // return user object with the their profile data
          return {
            ...user,
            email: user.email,
            name: user.nickname,
            image: user.image,
            id: user.id,
          }
        } catch (err) {
          console.error('로그인 에러', err);
        } 

 

그리고 cors에러는 발생하지 않고있습니다.

 

혹시 수정해야할 코드나, 참고해야할 부분이 있다면 알려주시면 감사하겠습니다.

 

 

 

답변 2

0

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

프론트 도메인과 서버 도메인이 서로 다르면 쿠키 전달이 매우 어렵습니다. 다른 상황인가요?

챠챠_님의 프로필 이미지
챠챠_
질문자

네 선생님

기존에는 도메인이 달랐고 탄력적 IP로 바꾼다음에는

프론트: xxx.com

백엔드: api.xxx.com 으로 도메인 맞춰서 작업했습니다.

그럼에도 incredentials만으로는 쿠키전달이 안되서

다른 비슷한 질문과 구글링해보고

클라이언트에서는 api router이용해서 서버함수를 실행하고 서버함수에서 쿠키를 가져와서 전달하면 작동한다는 글을 보고 따라해보니 되더라구요.

 

그래서 다른 api호출도 다 이런 방식으로 바궈야 401에러가 안날것 같은데 이런 방식으로 진행해도 될지 궁금합니다.

예: 클라이언트에서 /api/user/make 호출 -->
api/user/make/route.ts에서 서버함수 호출 --> 이후 데이터 리턴

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

도메인 맞추고 cookie의 Domain도 .xxx.com 이었나요? (앞에 점 붙어야함) 그래야 백엔드와 전달됩니다.

챠챠_님의 프로필 이미지
챠챠_
질문자

넵그렇습니다.

서버 도메인도 맞췄었습니다.

app.use(session({
  saveUninitialized: false,
  resave: false,
  secret: process.env.COOKIE_SECRET,
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production', // 프로덕션 환경에서만 secure 적용
    sameSite: process.env.NODE_ENV === 'production' ? 'None' : 'Lax', // 크로스 도메인 설정
    domain: process.env.NODE_ENV === 'production' ? '.zzimzzim.com' : undefined // 프로덕션 도메인 설정
  }
}));

 

이렇게 하고 클라이언트에선 요청할데 크리덴셜스 추가해서 했었습니다.

그럼에도 쿠키가 전달안됐어서

지금은

프론트: 로컬,

백엔드: api.xxx.com
에서 테스트 하고있으며

https://www.inflearn.com/questions/1106691/api-%EC%9A%94%EC%B2%AD-%EC%8B%9C-cookie-%EB%B3%B4%EB%82%B4%EB%8A%94-%EA%B2%83%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A7%88%EB%AC%B8

이 답변을 참고해서 진행했었습니다!

 

 

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

지금 https는 적용하셨나요? 그리고 로그인 시 쿠키가 네트워크 탭에 보입니다. 거기서 Domain, Secure 이런 거 다 맞는지 확인하세요. 쿠키 문제는 무조건 개인의 실수일 수밖에 없습니다. 네트워크 탭과 비교해보시면 됩니다.

챠챠_님의 프로필 이미지
챠챠_
질문자

https 적용전입니다.

 

실수하지 않았다면 credentials 옵션만으로 쿠키 공유가 되야한다는 뜻일까요?

 

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

네네 심지어 네트워크탭에 왜 쿠키가 안 심어지는지 이유까지 다 나옵니다

챠챠_님의 프로필 이미지
챠챠_
질문자

그렇다면 https://www.inflearn.com/questions/1106691/api-%EC%9A%94%EC%B2%AD-%EC%8B%9C-cookie-%EB%B3%B4%EB%82%B4%EB%8A%94-%EA%B2%83%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A7%88%EB%AC%B8
여기에 답변해주신 내용은
프론트: 로컬,

백엔드: ec2서버로
도메인이 달라서 해주신 답변이고,

지금 저와같이 도메인이 같게 한 상태라면 credentials 옵션맞으로 되야하는거군요... 혹시 https작업하지 않아서 발생할수도 있는걸까요? 아무리해봐도 안되서 위위 같이 돌아간건데 좀더 작업해보면서 찾아보도록 하겠습니다.

정말 감사합니다.

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

아뇨 https 없으면 secure만 false면 됩니다. 네트워크탭 response cookie탭 봐보세요

챠챠_님의 프로필 이미지
챠챠_
질문자

선생님 바쁘실텐데 소중한 답변 감사합니다.

그리고 죄송합니다

제가 정말 바보같은 실수를 했었더라구요..

제가 이 강의랑 넥스트강의를 같이 보면서 작업을 했는데 넥스트 강의에서 쿠키를 심어줄때 그냥 쿠키만 심어주고나서 잊고있다가 이번에 선생님이 답변주신 네트워크 > 쿠키탭을 보고 이상하다여겨서 봤더니 쿠키심을때 따로 값을 안주고 그냥 심기만해서 발생한 문제였습니다... ㅠ

 

담부턴 좀 더 살피고 질문할 수 있도록 하겠습니다.

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

챠챠_님의 문제는 클라이언트에서 API 호출 시 쿠키가 제대로 전달되지 않아 발생하는 것으로 보입니다. 이 문제는 특히 프로덕션 환경에서 CORS(Cross-Origin Resource Sharing) 설정과 쿠키 설정에 따라서 발생할 수 있습니다. 쿠키가 브라우저에 저장되지 않거나, 서버에 전달되지 않는 경우가 주 원인일 수 있습니다.

문제 해결을 위해 확인해야 할 핵심 포인트는 다음과 같습니다:
1. CORS 설정: Access-Control-Allow-Credentials 헤더와 Access-Control-Allow-Origin 헤더 설정이 브라우저에 제대로 전달되고 있는지 확인하세요. credentials: true는 올바르게 설정하셨으나, origin 설정에서 모든 클라이언트의 URL이 정확하게 매칭되는지 확인해야 합니다. origin: true를 사용하면 요청의 origin 헤더값을 그대로 반환해주어 동적으로 허용할 수 있으나, 보안 상의 이유로 실제 프로덕션에서는 사용할 때 주의가 필요합니다.

  1. 쿠키 설정: 쿠키의 도메인과 경로(Path) 설정을 확인하세요. 도메인이 설정되지 않았거나 경로가 잘못 설정된 경우 쿠키가 저장되지 않을 수 있습니다. 프론트엔드와 백엔드가 다른 도메인에서 서비스되고 있다면 쿠키의 Domain 속성을 적절히 설정해야 합니다.

  2. HTTPS 설정: 프로덕션 환경에서는 Secure 쿠키 옵션과 HTTPS를 사용하는 것이 일반적입니다. 현재 secure: false로 되어 있는데, 프로덕션 환경에서 HTTPS를 사용한다면 secure: true로 변경해야 쿠키가 제대로 전달됩니다.

관련 질문 & 답변 링크

당면한 문제 해결을 위한 제안:

  • 클라이언트와 API 서버 간의 도메인이 다르다면, 정확한 도메인 또는 IP를 origin 배열에 포함시키고, 서버와 클라이언트 간의 쿠키 공유를 위해 cookie 설정에서 Domain 속성을 올바르게 설정해야 할 수 있습니다.
  • 프로덕션 환경에서 HTTPS를 사용 중이라면 secure 쿠키 옵션을 적극 고려해 보세요.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

챠챠_님의 프로필 이미지
챠챠_

작성한 질문수

질문하기