実現したいこと
レスポンスヘッダーのSet-CookieにあるtokenをCookieに格納したい
前提
フロントエンド: React(v18), TypeScript, AWS Amplify
バックエンド: Python(v3.10),FastAPI, AWS app runner
認証ライブラリ: FastAPI JWT Auth
https://indominusbyte.github.io/fastapi-jwt-auth/usage/jwt-in-cookies/
ログインして利用するWebアプリケーションでフロントエンドとバックエンドは別々にデプロイしています。
ログイン後は、各エンドポイントごとでトークンチェックを行い、認証できない場合はトップ画面(ログイン前)へ遷移します。
発生している問題・エラーメッセージ
サーバーサイド側からSet-Cookieでクライアントにtokenを渡してもCookieにセットされず、次の画面で弾かれてトップ画面に戻ってしまう
(ログイン自体は成功してレスポンスが帰ってきます。)
ブラウザのデベロッパーツールでは、レスポンスヘッダーのSet-Cookieでトークンは確認できるが、!マークが表示されておりマウスホバーすると下記のメッセージが表示される
このSet-Cookie ヘッダーは、「SameSite」属性を指定しておらず、 デフォルトで「SameSite=Lax,」に設定されていましたが、トップレベルナビゲーション へのレスポンスではないクロスサイト レスポンスが送信元だったため、 ブロックされました。Set-Cookieには「SameSite=None」を設定し、 クロスサイトでの使用を有効にしておく必要があります。
該当のソースコード
@app.exception_handler(HTTPException) @router.post( "/api/v1/user/login", summary="ログイン" ) def user_login( data: UserLoginSchema, db: Session = Depends(raw_db), Authorize: AuthJWT = Depends(), ): try: user_login_res = AuthService.user_login(data, db, Authorize) if user_login_res["res"] == True: return user_login_res["data"] else: return JSONResponse(status_code=400, content={"error": user_login_res["message"]}) except HTTPException as e: logger.error(e.message) return JSONResponse(status_code=400, content={"error": "システムエラーが発生しました。"})
class AuthService: # ログイン @staticmethod def user_login( data: UserLoginSchema, raw_db: Session, Authorize: AuthJWT, ): # ~省略~ # email、パスワードが一致すればトークンを発行 issue_token(user.id, user.tenant_id, Authorize) data = { "result": True, "message": "Successfully login", "user_id": user.id, } return {"res": True, "data": data} else: return {"res": False, "message": "ログイン情報が正しくありません。"}
def issue_token( user_id: int, tenant_id: int, Authorize: AuthJWT ): user_claims = { "tenant_id": tenant_id, } access_token = Authorize.create_access_token( subject=user_id, user_claims=user_claims, expires_time=timedelta(hours=1), ) refresh_token = Authorize.create_refresh_token(subject=user_id) Authorize.set_access_cookies(access_token) Authorize.set_refresh_cookies(refresh_token)
class UserLoginSchema(BaseModel): email: EmailStr password: str
authjwt_secret_key = "secret" authjwt_token_location = {"cookies"} authjwt_cookie_secure = True authjwt_cookie_csrf_protect = True
試したこと
エラーメッセージに従いsamesiteをnoneにする
①FastAPI JWT Authのオプションを追加
authjwt_cookie_samesite = "none"
②直接設定を変える
def issue_token( user_id: int, tenant_id: int, Authorize: AuthJWT, res: Response = None ): user_claims = { "tenant_id": tenant_id, } access_token = Authorize.create_access_token( subject=user_id, user_claims=user_claims, expires_time=timedelta(hours=24), ) refresh_token = Authorize.create_refresh_token(subject=user_id) res.set_cookie( key="access_token_cookie", value=access_token, httponly=True, samesite="None", # SameSite=None を指定 secure=True, # HTTPS 接続でのみクッキーを送信 ) res.set_cookie( key="refresh_token_cookie", value=refresh_token, httponly=True, samesite="None", # SameSite=None を指定 secure=True, # HTTPS 接続でのみクッキーを送信 )
上記2つのパターンを試したところ、最初の認証はできるようになりログイン後の一番最初の画面は見れるようになりました。
ただブラウザのCookieに格納されない現象は改善できておらず、次のエンドポイントで弾かれてしまいます。
こちらについて、解決策をご存知の方がいらっしゃいましたらお力を貸していただけないでしょうか。
同様にCookieに格納されないにも関わらず上記の設定変更で、一番最初の画面が見れるようになった理由もわかっていません。
補足情報(FW/ツールのバージョンなど)
参考にした記事
https://qiita.com/sotaheavymetal21/items/fb7ae0e5d09c7b16a3c7
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/09/02 09:05
2023/09/02 16:33
2023/09/04 09:54
2023/09/04 13:09
2024/05/30 03:22