背景
drf+reactでローカルで開発中。
ログインでaccessトークンを発行していたのだが、cookieにsetされない。
特にエラーも出ない。しかしクッキーは保存されない。
クッキーについて調べてみた。
調査
アクセストークンを発行するのに以下のライブラリ使用。
dj-rest-auth,simpleJWT
調査には大きく3つ。
- Cookieの属性
- CSRF
- CORS
まずはCookieの属性。
その設定が以下。
REST_AUTH = {
'USE_JWT': True,
'JWT_AUTH_COOKIE': 'my-app-auth',
'JWT_AUTH_HTTPONLY':True,
'JWT_AUTH_COOKIE_USE_CSRF' : True,
# 'JWT_AUTH_SAMESITE':'None',
# 'JWT_AUTH_SECURE':True
}
from datetime import timedelta
# JWT setting
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(hours=1),
}
よく分からず設定していたので調査。
設定項目で必要そうなcookieの属性とやらを調べた結果。
Secure属性
https通信でしかcookieの送信は許さない。Secureに通信するための属性。
httpOnly属性
JavaScript の document.cookie では値を取得することができません。また document.cookie に対して HttpOnly 属性がついた値を Cookie に書き込むこともできません。xss攻撃に有効。
SameSite属性
A というサイトから B というサイトへリンクなどを経由して遷移するときに、ブラウザに保存されている B の Cookie を送信するかどうかのコントロールをおこなうための属性です。
ドメインの異なるサイト間でcookieを送信するのかってこと。
None、Lax、Strictの3つを設定可能。
NoneはなんでもOK。
Laxはgetだけ許す。
Strictは禁止。
NoneにしておけばOKだが、Secure属性をtrueにしとかないといけないらしい。
正味、localで開発する場合オリジンは異なるがドメインは異ならないのでNoneにする必要はないが、、、
次にCSRFトークン。
何となくの理解で、csrf攻撃を防ぐためのトークンという認識。
その設定が以下。
CSRF_TRUSTED_ORIGINS =["http://localhost:3000"]
# CSRF_COOKIE_SAMESITE ='None'
# CSRF_COOKIE_SECURE =True
csrfトークンに関してもsamesiteとsecureが設定可能。
次にCORS。
これは以前調査したので大体は理解している。
cors-headersライブラリ使用。
corsの設定。
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
]
CORS_ALLOW_METHODS = (
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
)
CORS_ALLOW_HEADERS = (
"accept",
"authorization",
"content-type",
"user-agent",
"x-csrftoken",
"x-requested-with",
"access-control-allow-origin",
"access-control-allow-credentials",
)
上から
リクエストを許可するオリジン、メソッド、header項目。
axios設定。
export const axiosInstance = axios.create({
baseURL: API_URL,
headers: {
"Access-Control-Allow-Origin": "http://localhost:3000",
"Access-Control-Allow-Credentials": "true",
},
});
~~~~~~~~
const response = await axiosInstance.post(
"/auth/login/",
{
email,
password,
},
{ withCredentials: true }
);
リクエストにクッキーを付与するためにwithCredentialsを。
解決策
localhostで行う場合は、samesite,secure設定はデフォルトでいい。(ライブラリの違いがあるためデフォルト値を確かめる。)
私が誤っていたのは2点。
- CORS_ALLOW_HEADERSに"access-control-allow-credentials"を設定したら、リクエストにクッキーを付与する許可になると思っていた。(access-control-allow-originがそうだったから、、同じようにすればいいと、、、、、)
- axiosの設定で"Access-Control-Allow-Credentials": "true"は必要ない。
CORSでCookieのやり取りをした場合、Access-Control-Allow-Credentialsをtrueにしないといけない。
Access-Control-Allow-Credetials=trueってのを設定するためにはバックエンドは
CORS_ALLOW_CREDENTIALS
という値を設定する必要がある。(drfだったら)
またフロントもaxiosのheadersに"Access-Control-Allow-Credentials": "true"を書いても意味ない。
withCredentials:trueでCookieなどの資格情報を使用することができる。
gitのissueにもあった。
https://github.com/iMerica/dj-rest-auth/issues/192
express使ったときは
にAccess-Control-Allow-Credetials=trueを設定する方法が載っていた。
httpsでローカルでやりたい人はコンテナを使えば楽。
steveltn/https-portalイメージを使用してみたがとても簡単にhttps設定ができた。