WEGO ) 프론트의 개발환경에서 현재 배포된 백엔드 서버의 쿠키 공유가 불가능한 이슈

▪︎ 백엔드 서버와의 쿠키 공유

▫︎ 개발 환경에서 Set-Cookie로 받은 쿠키가 사라진다?

우리 프로젝트에서는 로그인을 하면 서버에서 Set-Cookie를 통해 인증 토큰을 심어주고, 이후 인증이 필요한 요청 (로그인이 필요한 요청) 시 서버에서 프론트 요청의 쿠키를 읽어 인증 여부를 검증하고 그에 따른 응답을 반환하도록 설계되어있다.

배포 환경에서는 해당 로직이 잘 동작하였으나 개발 환경에서 받아온 쿠키가 계속해서 사라지는 현상이 일어났다.

image.png

▫︎ 문제 찾아보기

1️⃣ cors 설정이 제대로 안되어있는 것은 아닐까?

우선 백엔드 측에 cors 설정이 되어있는지를 확인해보았다. 백엔드 측에서는 개발환경과 배포환경에 대해 조건부로 잘 설정해주었다고 답변받았다. 혹시 실수가 있었던 것은 아닐까? next.js 의 rewrites 기능을 이용하여 프록시를 통해 cors를 우회하여 테스트를 해보았다.

1
2
3
4
5
6
7
8
9
// next.config.ts
rewrites: async () => {
return [
{
source: '/api/:path*',
destination: `${process.env.NEXT_PUBLIC_BASE_URL}/:path*`,
},
];
},

$ 여전히 쿠키는 사라진다. cors 문제는 아니다.


2️⃣ SameSite 를 None 으로 설정하면 해결되지 않을까? ( + Secure )

크로스 사이트 요청 시 쿠키 전송을 허가하는 설정인 SameSite=None 을 쿠키에 설정해주면 어떨까? 우선 SameSite를 설정하기 위해서는 Secure 설정또한 추가로 해줘야 한다.

image.png

$ 해당 설정을 해주어도 동일한 현상이 일어났다.


3️⃣ HTTP 의 문제

문제 해결을 위해 쿠키의 각 속성에 대한 정보를 찾아보았다. Secure 설정을 위해서는 반드시 HTTPS 요청이 필요하다. HTTPHTTPS 간의 scheme 차이 때문에 발생하는 문제였다는 것을 찾아냈다.

정리해보자면 SameSite=None을 사용하기 위해서는 반드시 Secure 플래그가 필요하고, 이를 위해서는 다시 HTTPS가 필요하다.

mkcert 로 로컬 인증서를 생성하고 pakage.json의 script에서 “dev” 명령어에 —experimental-https 옵션을 사용하여 https://localhost:3000 에서 요청을 보내보았다.

1
2
3
4
// package.json
"scripts": {
"dev": "next dev -H localhost --experimental-https",
...

$ https 설정을 하여 SameSite=None, Secure 설정을 해줘도 쿠키는 사라졌다.


4️⃣ 크로스 도메인 문제인 것 같다. 쿠키를 구워줄 때, 개발환경에서의 요청이라면 Domain 값을

    **localhost로 설정하면 되지 않을까?**

마지막으로 살펴볼만한 문제는 쿠키의 Domain 속성이다. 쿠키의 도메인은 .we-go.world 로 되어있다. 배포 주소가 we-go.world 이기 때문에 배포 사이트에서는 정상적으로 동작하고, localhost 인 개발환경에서는 정상적으로 동작하지 않는 것이 아닐까?

백엔드와 상황을 공유하니 백엔드에서 요청한 클라이언트의 Origin을 읽어 그에 따라 조건부로 Domain을 설정해주기로 했다.

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
@Component
public class CookieProvider {
@Value("${cookie.domain}")
private String domain;

@Value("${security.jwt.token.expire-length}")
private String accessTokenExpire;

public ResponseCookie accessTokenCookie(String accessToken, HttpServletRequest request) {
String origin = request.getHeader("Origin");
String referer = request.getHeader("Referer");

boolean isLocalhost = (origin != null && (origin.contains("localhost") || origin.contains("127.0.0.1")))
|| (referer != null && (referer.contains("localhost") || referer.contains("127.0.0.1")));

ResponseCookie.ResponseCookieBuilder cookieBuilder = ResponseCookie.from("accessToken", accessToken)
.httpOnly(true)
.secure(true)
.path("/")
.maxAge(Duration.ofSeconds(Long.parseLong(accessTokenExpire)))
.sameSite("None");

if (!isLocalhost) {
cookieBuilder.domain(domain);
}

return cookieBuilder.build();
}
}

그러나 동일하게 쿠키의 Domain 부분에는 .we-go.world 가 설정되어있다.

image.png


5️⃣ 서버는 자신의 도메인이 아닌 다른 도메인에 쿠키를 설정할 수 없다.

api 요청 시 백엔드도 localhost 에서 실행되었을 때에는 쿠키가 정상적으로 설정되었겠지만, 우리는 지금 배포된 백엔드에 테스트를 하려고 했다. 그래서 Domain이 우리가 의도한 대로 설정되지 않았다.


6️⃣ 로컬 호스트 환경에서도 도메인 일치를 위해 Custom Domain을 설정하자.

프론트의 로컬 호스트 환경에서 Custom Domain을 설정하여 프론트와 백엔드가 동일한 베이스 도메인 하에서 테스트할 수 있다면 해결되지 않을까?

/etc/hosts 파일을 수정하여 localhost 도메인을 front.we-go.world로 설정하고, 추가로 개발 모드 실행에서 도메인을 명시해주었다.

1
2
3
4
5
// package.json
...
"scripts": {
"dev": "next dev -H front.we-go.world --experimental-https",
...

image.png

▪︎ 정리

프론트와 백엔드 간의 쿠키 공유를 위해서는 서로의 베이스 도메인을 일치시켜야한다. 또한 서로가 동일한 도메인이 아닌 경우, 쿠키의 SameSite=NoneSecure 설정이 필요하며 이를 위해서는 프론트의 개발 환경에서 HTTPS 를 사용해야만 한다.

포스팅: 개발 환경에 HTTPS 및 Custom Domain 설정하기