Firefox中React Fetch未携带Cookie的Discord OAuth2问题
授权流程
- React 应用(localhost:端口1)中通过
window.location.href跳转到后端 OAuth2 授权端点(localhost:端口2/api/oauth2/authorization/discord)
代码实现:async function onSubmit() { try { window.location.href = "http://test.local:port2/api/oauth2/authorization/discord"; } catch (error) { console.log(error) } } - 向
test.local发送GET请求,后端返回HTTP 302重定向至Discord授权页,同时携带Set-Cookie响应头
响应头内容:HTTP/1.1 302 Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers Set-Cookie: oauth2_auth_request=long_cookie_value; Path=/; Max-Age=180; Expires=Sun, 29 Jan 2023 14:13:47 GMT; SameSite=None X-Content-Type-Options: nosniff X-XSS-Protection: 0 Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Location: https://discordapp.com/oauth2/authorize?response_type=code&client_id=...&redirect_uri=http://localhost:5173/login Content-Length: 0 Date: Sun, 29 Jan 2023 14:10:47 GMT Keep-Alive: timeout=60 Connection: keep-alive - 用户看到Discord登录页面
- 在浏览器中直接访问
http://test.local:port2,可确认Cookie已正确设置 - 用户登录Discord后,Discord重定向至
http://localhost:端口1/login?code=...&state=... - React应用发送fetch请求到后端的code回调端点:
代码实现:
请求头内容:fetch( `http://test.local:port2/api/login/oauth2/code/discord?code=${searchParams.get("code")}&state=${searchParams.get("state")}`, { credentials: "include", } ) .then((res) => res.json()) .then((data) => console.log(data))GET /api/login/oauth2/code/discord?code=...&state=... HTTP/1.1 Host: sss.test:8081 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0 Accept: */* Accept-Language: pl,en-US;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:5173/ Origin: http://localhost:5173 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache
结果对比
- 预期结果:fetch请求需携带步骤2中设置的
oauth2_auth_requestCookie,以验证授权流的两次请求来自同一源 - 实际结果:Cookie未被携带
观察结果
- 直接在浏览器地址栏访问
http://test.local:port2/api/login/oauth2/code/discord?code=...&state=...时,Cookie会被正常携带
请求头内容:GET /api/login/oauth2/code/discord?code=...&stat=... HTTP/1.1 Host: sss.test:8081 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: pl,en-US;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive Cookie: oauth2_auth_request=long_cookie_value Upgrade-Insecure-Requests: 1 Pragma: no-cache Cache-Control: no-cache - 前端与后端同域名时,整个流程可正常工作
环境与配置说明
- 仅开发环境使用HTTP,后续将切换至HTTPS
- 因Chrome会阻止非安全环境下的
SameSite=NoneCookie,故在Firefox中测试 - Spring Security CORS配置:
... .cors() .configurationSource(request => { final CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); config.setAllowCredentials(true); config.setAllowedOrigins(List.of("http://localhost:5173")); return config; }) ... - 前端需从该fetch请求的响应中获取JWT Token,用于后续接口认证
内容的提问来源于stack exchange,提问作者Wojciech Drzewiecki
相关产品推荐
相关产品推荐

