diff --git a/.claude/rules/backend/auth-security.md b/.claude/rules/backend/auth-security.md index 7c8baf4c..be25235d 100644 --- a/.claude/rules/backend/auth-security.md +++ b/.claude/rules/backend/auth-security.md @@ -8,7 +8,7 @@ paths: ## 認証 - **認証方式**: GitHub OAuth のみ。パスワード認証は実装していない(`users` テーブルにパスワード関連カラムは持たない、OAuth 専用設計) -- **JWT**: `python-jose[cryptography]`、RS256 署名(`JWT_PRIVATE_KEY` / `JWT_PUBLIC_KEY`) +- **JWT**: `PyJWT[crypto]`、RS256 署名(`JWT_PRIVATE_KEY` / `JWT_PUBLIC_KEY`) - **トークン有効期間**: - アクセストークン: 15 分(Cookie 名 `access_token`) - リフレッシュトークン: 7 日(Cookie 名 `refresh_token`) diff --git a/README.md b/README.md index e00b20dc..cb19b42a 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ GitHub活動分析、ブログ連携による発信力を集計 | AI / LLM | Anthropic Claude / OpenAI GPT / Google Gemini(ユーザー選択式・ADR-0013)、ローカルは Ollama | | 決済 | Stripe Checkout(クレジット購入・従量課金 / ADR-0012) | | データベース | Turso (libSQL / SQLite 互換、`sqlalchemy-libsql`) | -| 認証 | JWT Cookie (python-jose), bcrypt, GitHub OAuth | +| 認証 | JWT Cookie (PyJWT), bcrypt, GitHub OAuth | | 暗号化 | Fernet(フィールド暗号化) | | PDF出力 | WeasyPrint(職務経歴書), ReportLab(分析レポート補助) | | インフラ | GCP (Cloud Run, Artifact Registry, Secret Manager), Turso, Cloudflare Pages | diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index 5528d515..a30e3c3a 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -78,8 +78,8 @@ DevForge は多くのオープンソースソフトウェア(OSS)に支え | [pydantic](https://github.com/pydantic/pydantic) | 2.13.4 | MIT | | [pydyf](https://www.courtbouillon.org/pydyf) | 0.12.1 | BSD License | | [PyGithub](https://github.com/pygithub/pygithub) | 2.9.1 | GNU Library or Lesser General Public License (LGPL) | +| [PyJWT](https://github.com/jpadilla/pyjwt) | 2.13.0 | MIT | | [python-dotenv](https://github.com/theskumar/python-dotenv) | 1.2.2 | BSD-3-Clause | -| [python-jose](https://github.com/mpdavis/python-jose) | 3.5.0 | MIT License | | [python-multipart](https://github.com/Kludex/python-multipart) | 0.0.32 | Apache-2.0 | | [redis](https://github.com/redis/redis-py) | 8.0.1 | MIT | | [reportlab](https://www.reportlab.com/) | 5.0.0 | BSD License | diff --git a/backend/app/core/security/auth.py b/backend/app/core/security/auth.py index 5932c198..75bfe85a 100644 --- a/backend/app/core/security/auth.py +++ b/backend/app/core/security/auth.py @@ -4,8 +4,8 @@ from datetime import datetime, timedelta, timezone from typing import NoReturn +import jwt from fastapi import Depends, Request, status -from jose import JWTError, jwt from sqlalchemy.orm import Session from ...db import get_db @@ -39,7 +39,7 @@ def validate_jwt_key_pair() -> None: algorithm=_ALGORITHM, ) jwt.decode(tok, get_jwt_public_key(), algorithms=[_ALGORITHM]) - except JWTError as e: + except jwt.PyJWTError as e: raise RuntimeError( f"JWT 鍵ペアが不正です(秘密鍵と公開鍵が一致しないか、フォーマットが壊れています): {e}" ) from e @@ -86,7 +86,7 @@ def _decode_token(token: str) -> dict: """JWT をデコードしてペイロードを返す。失敗時は 401 を送出する。""" try: return jwt.decode(token, get_jwt_public_key(), algorithms=[_ALGORITHM]) - except JWTError: + except jwt.PyJWTError: _raise_auth_failed("jwt_decode_error", with_bearer_header=True) diff --git a/backend/requirements.txt b/backend/requirements.txt index 73670e73..ad966838 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -11,7 +11,7 @@ python-dotenv==1.2.2 reportlab==5.0.0 google-cloud-storage==3.12.0 pytest==9.1.1 -python-jose[cryptography]==3.5.0 +PyJWT[crypto]==2.13.0 httpx==0.28.1 # マルチプロバイダ LLM(ADR-0013)。Gemini = google-genai、GPT = openai。 # Gemini / Anthropic は Vertex AI(SA→ADC)経由(ADR-0015)。anthropic[vertex] の diff --git a/backend/tests/auth/test_token_manager.py b/backend/tests/auth/test_token_manager.py index f7bb79de..84091aa9 100644 --- a/backend/tests/auth/test_token_manager.py +++ b/backend/tests/auth/test_token_manager.py @@ -7,6 +7,7 @@ from unittest.mock import AsyncMock, MagicMock, patch +import jwt import pytest from app.core.security.auth import ( create_access_token, @@ -14,7 +15,6 @@ ) from app.core.settings import get_cookie_samesite, get_cookie_secure from app.routers.auth.token_manager import GITHUB_OAUTH_STATE_COOKIE -from jose import jwt from conftest import _test_public_key, auth_header