Express CORS Cookie

## はじめに

備忘録です。
下記の構成でアプリケーションを作成する際にCORSを解放する必要がありました。
ExpressでJSON形式のAPI
フロントエンドでReact

CORSを解放するのはCookieを設定したいためであることが多いと思います。
ついでに載せておきます。

## CORSとは？
*CROSS-ORIGIN-RECOSE-SHARERING*
*オリジンが違う場合でもアクセスできるようにする処理です*

SPAの場合
バックエンドはlocalhost:4000
フロントエンドはlocalhost:3000
といったかんじで同一オリジンではないので、Cookie関連の処理ができません。
正確にいうとPOSTリクエストでCookie関連の処理ができません。 GETはできたはず？


## cors
こういった設定はheaderというところに設定を記述します。
npmには便利なパッケージがあるので使います。
```ts
import cors from "cors"

app.use(
  cors({
    // cookieの送受信を可能にする
    credentials: true,
    // 許可するドメイン登録
    origin: 'url',
  }),
);

// 複数ある場合の解放方法
origin: ['url1', 'url2'],
```

*上記は下記のようなことを行っています。*
```js
// packageを使わずに手動で設定する場合
app.use(function (req, res, next) {
  // アクセスを許可するオリジン(ドメイン)を登録
  res.header("Access-Control-Allow-Origin", "url");
  // 許可したドメインでCookie関連の処理を許可するか設定
  // Access-Control-Allow-Originを*で全て許可していた場合tureにできない
  res.header("Access-Control-Allow-Credentials", true);
  // expressの機能で、次の処理に進ませる
  next();
});
```

`Access-Control-Allow-Originを*で全て許可していた場合tureにできない`の部分ですが、
*を利用して全ての接続を許可することができるのですが、良くないみたいです。 ネットサーフィンしている時にどこかで読みました。

ここまでがフロントエンドとのCookieの送受信を可能にするための`CORSの`設定です。

---

## cookieの保存
*express標準の機能でCookieの保存ができます*
```js
// 下記の構成になっています。
// 下記の記述があると、HTTPレスポンスヘッダに対して、Set-Cookieというものを付与します。
// クライアントはその値を見て、Cookieを自動で保存します。
// つまり、リクエストを飛ばせば、特に何をするまでもなく自動で保存されます。
res.cookie("key", "value", {option})
```

```js
// 下記のエンドポイントを叩くと、`name: hogehoge`がCookieに保存されます。
app.get('/', (req, res) => {
  res.cookie('name', 'hogehoge', { 
    sameSite: 'none',
    secure: true,
    maxAge: 24 * 60 * 60 * 1000,
    httpOnly: true,
  });
  res.send('Cookie has been set');
});
```
*オプションの解説をします*
```js
// 他のドメイン(別オリジン)からのPOSTでもCookieの送受信を許可
sameSite: 'none'

// HTTPSで暗号化された通信以外は拒絶する (HTTP接続を禁止)
// localhostの場合HTTPでも接続できる
// ブラウザによってsameSite noneでsecureがfalseの場合Cookieの処理を受け付けなくなっている
// Chromeのような主要ブラウザではそうなっているのでほぼ必須と言える
// つまり、sampeSiteを'none'にする場合必ずtrueである必要がある
secure: true,

// Cookieの有効期限
// ms秒で設定します。 下記は24Hです。
maxAge: 24 * 60 * 60 * 1000,

// JavaScriptでアクセスできなくする
// HTTPでしか接続できなくするものではないです (HTTPS接続を禁止するものではないです)
// この設定により不正なサイトにユーザーが誘導され、Cookieの値が抜き取られることを防ぎます
httpOnly: true, 
```

いろいろ説明してきましたが、クロスオリジンでCookieをやりとりするための必須項目は下記3つです。
- CORSの設定
- sameSite: true (Cookie保存時)
- secure: true (Cookie保存時)

他は最悪なくても動きますが、セキュリティ的に本番環境では設定した方が良いです

---

## cookieParser
*リクエストからcookieを取得するためのpackage*
ExpressはCokkieの保存には追加packageが不要ですが、Cookieの取得には追加のpackageが必要です。
*自力でできないこともないですが、かなり面倒です*
```ts
import cookieParser from "cookie-parser"

app.use(cookieParser());

app.get('/', (req, res) => {
  // 下記のようのreqestからcookieの値を取得できる
  const cookieValue = req.cookies.name;
  res.json({ name: cookieValue })
});
```



---

## フロントエンド側の話も
*axiosを使う場合を例に挙げてみます*
*ちなみにfetchも同じで、デフォルトではCookieの送信や受信時のCookie追加の処理をしません*
*fetchの場合は設定値の仕方が若干変わるので調べてみてください*
```ts
// デフォルトではCookieの送信や受信後の処理を行わない
// withCredentialsをtureに設定する
const getCookie = async () => {
  const response = await axios.get(URL, {
    withCredentials: true,
  });
  console.log(response.data);
};
```

## 終わりに
Expressは情報が比較的多いのですが、SPA特有の設定調べるのに時間がかかりますね・・・

Cookieは検証ツールのApplicationタブから見ることができます。
フロントエンドからAPIを叩いた際、検証ツールのNetworkタブでheader情報を確認することができます。
Cookieの追加の場合Responseの部分に`Set-Cookie`があるはずです。
自分でいろいろ検証したい場合は参考にしてください