質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Cookie

HTTPにおけるCookieとは、クライアントのウェブブラウザ上に保存された一時的なデータを指します。クライアント側のJavaScriptでも、サーバー側のHTTPヘッダーでもクッキーの読み書き・修正・削除が可能です。

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

CSRF

クロスサイトリクエストフォージェリ (Cross site request forgeries、CSRF)は、 外部Webページから、HTTPリクエストによって、 Webサイトの機能の一部が実行されてしまうWWWにおける攻撃手法です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

965閲覧

レスポンスヘッダーのSet-CookieにあるtokenをCookieに格納したい

abutoku

総合スコア0

Cookie

HTTPにおけるCookieとは、クライアントのウェブブラウザ上に保存された一時的なデータを指します。クライアント側のJavaScriptでも、サーバー側のHTTPヘッダーでもクッキーの読み書き・修正・削除が可能です。

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

CSRF

クロスサイトリクエストフォージェリ (Cross site request forgeries、CSRF)は、 外部Webページから、HTTPリクエストによって、 Webサイトの機能の一部が実行されてしまうWWWにおける攻撃手法です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2023/09/01 15:08

編集2023/09/01 15:11

実現したいこと

レスポンスヘッダーの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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

次のエンドポイントで弾かれてしまいます。

よくある原因を一つ挙げるなら
Cookieはブラウザ側でGETとPOSTを個別に管理しているのを
サーバ側で統合させる処理をしていないのがあり
処理をしていないとリクエストヘッダは下記の構成でサーバに送付されてしまいます。
※GET,POST何れかのキーが無い場合もブラウザ側で個別に管理しています。

<キーAAA>=<GET用の値>;<キーAAA>=<POST用の値>

投稿2023/09/02 08:25

mamekinkanmame

総合スコア39

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

abutoku

2023/09/02 09:05

ご回答ありがとうございます。 レスポンスヘッダーのSet-Cookieで返ってきたtokenを、 検証ツールで確認するとCookie格納されていない状態です。 現時点ではクライアントからサーバーにCookieを送付できていない気がしています。
mamekinkanmame

2023/09/02 16:33

申し訳ありません。下記部分を読み飛ばしました。 >!マークが表示されておりマウスホバーすると下記のメッセージが表示される 「SameSite」属性については下記URLを参照下さい。Cokkie文字列に追記するだけなので 難しくないと思います。 https://www.javadrive.jp/javascript/webpage/index18.html
abutoku

2023/09/04 09:54

ありがとうございます! 説明が足りておらず申し訳ありません。 「SameSite」属性については、試したこと①、②でNoneにすることができました。(検証ツールで確認し!マークも消えました。) そうすると挙動が変わり、最初の画面がみれるようになりました。 この時点でもトークンがセットされておらず次のエンドポイントにアクセスするときに弾かれるという状況です。 現在の問題点は下記の2点です。 ・検証ツールの!が消えた状態でも、トークンがセットできない原因 ・SameSiteをNoneにしたときに最初だけ認証される理由が不明
mamekinkanmame

2023/09/04 13:09

refresh_tokeの値とかサーバ側で値デバッグで確認して頂けますか。 空文字になっている気がします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問