home
home

[cookie] 開発中にlocalhostと別ドメインのAPIサーバ間のcookieの受け渡しがうまくできないときはReactのproxyを設定するといい

2021/11/18

やりたいこと

APIとクライアントアプリを別のプロジェクトとして開発しているとき、クライアントアプリをlocalhostで起動させて、APIのテストサーバと通信させる。そのとき認証でcookieが必要になるけど、samesiteとかsecureの問題でcookieの受け渡しができないので、ちゃんとcookieの受け渡しを行えるようにしたい。

解決法

cookieとかsamesiteとかsecureとかについていろいろ調べたけど、まず解決方法を記述しておく。調査内容に関してはあとで書く。

フロント(React)側の設定

(async () => {
  try {
    await fetch(
      '/api/hoge',
      {
        method: 'GET',
        credentials: 'include',
        mode: 'cors',
      },
    )
      .then((res) => res.json())
      .then((json) => console.log(json));
  } catch (e) {
    console.log(e);
  }
})();
# package.json

{
  "proxy": "https://hoge.com", // APIサーバのURL
}

こうするとhttp://localhost:3000に対するリクエストのうち、Acceptヘッダがtext/html以外のリクエストを全てhttps://hoge.comにproxyします。 Reactアプリからfetch("/api/auth")を実行した場合、ブラウザはhttp://localhost:3000/api/authにリクエストを投げ、開発サーバがhttps://hoge/api/authにproxyします。 ブラウザから見ればhttp://localhost:3000/apiにアクセスしているように見えるのでSameOriginポリシーに引っかかりません。

引用元: 知っていると捗るcreate-react-appの設定

サーバ側設定

import express from 'express';
import index from './routes/index';
import { config } from 'dotenv';
import cors from 'cors';
import session from 'express-session';
import passport from './auth';

const app = express();

// ミドルウェア
app.use(session({
  secret: 'secret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    path: '/',
    maxAge: 2592000,
    httpOnly: false,
  }
}));
app.use(passport.initialize());
app.use(passport.session());

// cors
app.use(cors({ origin: 'http://localhost:3000', credentials: true }))

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

config();
const port = process.env.PORT || 3000;

// - ルーティング -
app.use('/api', index);

app.listen(
  port,
  () => {
    console.log(`Express start on port ${port} !!`);
  },
);

調査内容

なぜクロスオリジン間(APIのテストーサーバとocalhost)でcookienの受け渡しができなかったのか。

  • samesite
    • セキュリティ的な問題で、cookieは同origin間でしか受け渡しできないようになっている
    • これをクロスドメイン間で解決するにはsamesiteをnoneにする必要がある。
    • ただsamesiteをnonenにするとsecureをtrueにしなければいけなくなって、このsecureをtrueにするとhttps://間でしかcookieの受け渡しができなくなる。localhostはhttp://なので、cookieの受け渡しができない。詰み。
    • localのPCのdomaineをAPIサーバのドメインにしてみたりしたけどうまくいかなかった。

終わり

ずっとバックエンドの方でcookieの設定をいじっていたけれど、最終的にはReactの設定でなんとかなってよかった💪

バックエンドとフロントエンドを分断して開発するのは各々の責務に集中できていいと思うけど、そのせいでいろんな問題が起きるの面倒だなあとおもった。せせりさんがRailsで4日間くらいでアプリつくってて、自分もPHPだけでアプリケーションつくってるときのほうが考えること少なかった気がするなあと思ったり思わなかったり。

アプリ開発、もっとシンプルになってくれ🙏

sponsored link