<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Samesitelax on Joonlog</title><link>https://joonlog.github.io/tags/samesitelax/</link><description>Recent content in Samesitelax on Joonlog</description><generator>Hugo -- gohugo.io</generator><language>ko-kr</language><lastBuildDate>Wed, 22 Oct 2025 09:00:00 +0900</lastBuildDate><atom:link href="https://joonlog.github.io/tags/samesitelax/index.xml" rel="self" type="application/rss+xml"/><item><title>깃허브 코드로 배포한 Pokerogue 앱에서 구글/디스코드 외부 로그인이 실패하는 이슈</title><link>https://joonlog.github.io/p/%EA%B9%83%ED%97%88%EB%B8%8C-%EC%BD%94%EB%93%9C%EB%A1%9C-%EB%B0%B0%ED%8F%AC%ED%95%9C-pokerogue-%EC%95%B1%EC%97%90%EC%84%9C-%EA%B5%AC%EA%B8%80/%EB%94%94%EC%8A%A4%EC%BD%94%EB%93%9C-%EC%99%B8%EB%B6%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%9D%B4-%EC%8B%A4%ED%8C%A8%ED%95%98%EB%8A%94-%EC%9D%B4%EC%8A%88/</link><pubDate>Wed, 22 Oct 2025 09:00:00 +0900</pubDate><guid>https://joonlog.github.io/p/%EA%B9%83%ED%97%88%EB%B8%8C-%EC%BD%94%EB%93%9C%EB%A1%9C-%EB%B0%B0%ED%8F%AC%ED%95%9C-pokerogue-%EC%95%B1%EC%97%90%EC%84%9C-%EA%B5%AC%EA%B8%80/%EB%94%94%EC%8A%A4%EC%BD%94%EB%93%9C-%EC%99%B8%EB%B6%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%9D%B4-%EC%8B%A4%ED%8C%A8%ED%95%98%EB%8A%94-%EC%9D%B4%EC%8A%88/</guid><description>&lt;blockquote&gt;
&lt;p&gt;공식 rogueserver 코드의 쿠키 설정 버그로 인해 구글 OAuth 로그인이 작동하지 않는 이슈&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="환경"&gt;환경
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Vite 기반 React 프론트엔드와 Go 기반 백엔드 그리고 Mariadb로 구성&lt;/li&gt;
&lt;li&gt;K8S + HAProxy를 통한 외부 접근&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="문제-상황"&gt;문제 상황
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;일반 계정 로그인은 정상 작동&lt;/li&gt;
&lt;li&gt;구글/디스코드 계정 연결 시도 시 에러:
&lt;ol&gt;
&lt;li&gt;일반 로그인 후 설정 메뉴에서 구글 연결 클릭&lt;/li&gt;
&lt;li&gt;구글 OAuth 인증 완료&lt;/li&gt;
&lt;li&gt;메인 화면으로 리다이렉트되지만 설정이 저장되지 않고 새로고침만 됨&lt;/li&gt;
&lt;li&gt;로그아웃 후 구글로 직접 로그인 시도 시 로그인 실패&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="에러-분석"&gt;에러 분석
&lt;/h2&gt;&lt;h3 id="1-백엔드-로그-분석"&gt;1. 백엔드 로그 분석
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl logs -n pokerogue pokerogue-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2025/10/14 23:02:24 [DEBUG] Google token response status: 200
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2025/10/14 23:02:24 [DEBUG] Successfully extracted userId: 102118711772610730702
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2025/10/14 23:02:47 /account/info: missing token
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;구글 OAuth 토큰 교환은 성공 (userId 추출 완료)&lt;/li&gt;
&lt;li&gt;DB에 googleId도 정상 저장됨 확인&lt;/li&gt;
&lt;li&gt;하지만 세션 토큰이 누락되어 로그인 상태 유지 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-브라우저-네트워크-탭-분석"&gt;2. 브라우저 네트워크 탭 분석
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Request: GET /api/auth/google/callback
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Response: 303 See Other
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Set-Cookie: pokerogue_sessionId=...; SameSite=Strict; Domain=pokerogue.net
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Sec-Fetch-Site: cross-site
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;문제점 발견:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Domain=pokerogue.net&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;공식 pokerogue URL로 하드코딩 되어 있어 현재 도메인과 불일치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SameSite=Strict&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;구글에서 돌아오는 요청이 &lt;code&gt;cross-site&lt;/code&gt;이므로 쿠키가 전송되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;OAuth 리다이렉트 흐름:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pokerogue.&amp;lt;도메인&amp;gt;&lt;/code&gt; → &lt;code&gt;accounts.google.com&lt;/code&gt; → &lt;code&gt;pokerogue.&amp;lt;도메인&amp;gt;/callback&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SameSite=Strict&lt;/code&gt;는 같은 사이트 내부 요청에만 쿠키 전송&lt;/li&gt;
&lt;li&gt;구글에서 돌아오는 것은 cross-site 요청으로 간주되어 쿠키 차단&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="해결-방법"&gt;해결 방법
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;api/endpoints.go&lt;/code&gt; 파일의 쿠키 설정 수정:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;pokerogue_sessionId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SameSiteLaxMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Strict → Lax 변경&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// &amp;#34;pokerogue.net&amp;#34; → &amp;#34;&amp;#34; 변경&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;변경 사항&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Domain: &amp;quot;&amp;quot;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;빈 문자열로 설정하여 현재 도메인 자동 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SameSite: http.SameSiteLaxMode&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Strict&lt;/code&gt; → &lt;code&gt;Lax&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Lax&lt;/code&gt;는 안전한 cross-site GET 요청(OAuth 콜백 포함)에서 쿠키 전송 허용&lt;/li&gt;
&lt;li&gt;OAuth 표준에서 권장하는 설정&lt;/li&gt;
&lt;li&gt;여전히 CSRF 공격 방어 가능 (위험한 POST 요청은 차단)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="결과"&gt;결과
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;일반 로그인 → 구글 계정 연결 → 로그아웃 → 구글 직접 로그인 모두 정상 작동&lt;/li&gt;
&lt;li&gt;세션 쿠키가 올바르게 설정되어 로그인 상태 유지&lt;/li&gt;
&lt;li&gt;브라우저 네트워크 탭에서 &lt;code&gt;Set-Cookie: ...; SameSite=Lax&lt;/code&gt; 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="참고"&gt;참고
&lt;/h3&gt;&lt;p&gt;OAuth를 사용하는 많은 프로젝트에서 동일한 이슈가 발생했으며, 모두 &lt;code&gt;SameSite=Lax&lt;/code&gt;로 해결&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/oauth2-proxy/oauth2-proxy/issues/1663" target="_blank" rel="noopener"
&gt;https://github.com/oauth2-proxy/oauth2-proxy/issues/1663&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/grafana/grafana/pull/18332" target="_blank" rel="noopener"
&gt;https://github.com/grafana/grafana/pull/18332&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>