「JWTでログイン機能を作ろう」と思ったら、気づいたら5個もライブラリを入れていた……なんてこと、ありませんか?😅

python-jose、passlib、Redis、自作RBAC……パズルみたいにライブラリを組み合わせていくのは、正直しんどいですよね。そんな課題にズバッと切り込む面白い比較記事が話題になっています。

🔐 本格的なAuth、実は「意外と部品が多い」

security authentication
security authentication / Photo by Pixabay via Pexels

「JWT認証」と一口に言っても、実際に本番で使えるレベルにするには、こんなピースが必要になります。

  • ✅ パスワードハッシュ(Argon2id推奨。新規プロジェクトでbcryptはもう古い)
  • ✅ JWTの署名と検証
  • ✅ RBAC(ロールベースアクセス制御):管理者・一般ユーザーの権限管理
  • ✅ ログアウト時のトークン失効(ブラックリスト管理)

これをFastAPIで実装しようとすると、自然と python-jose + passlib + Redis + 自作RBACの組み合わせになりがちです。

⚡ FastAPIでの典型的な実装イメージ

ポイントをまとめるとこんな感じです👇

# FastAPI + python-jose + passlib の典型パターン
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta, timezone

SECRET_KEY = "your-secret-key"  # 例示用。本番ではコードに直接書かず環境変数などから読み込む
ALGORITHM = "HS256"

# パスワードハッシュ設定(Argon2idを推奨)
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")

# トークン失効用ブラックリスト(本番はRedisに替える)
blacklist: set[str] = set()

app = FastAPI()

# トークンはURLではなくAuthorizationヘッダー(Bearer)から受け取る
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def create_token(data: dict, expires_delta: timedelta = timedelta(minutes=30)):
    """JWTトークンを生成する"""
    payload = data.copy()
    payload["exp"] = datetime.now(timezone.utc) + expires_delta
    return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)

def verify_token(token: str = Depends(oauth2_scheme)):
    """トークンを検証 + ブラックリストチェック"""
    if token in blacklist:
        raise HTTPException(status_code=401, detail="トークンは無効化されています")
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        raise HTTPException(status_code=401, detail="トークンが不正です")

def require_role(required_role: str):
    """RBACの簡易実装:ロールを確認するデコレータ的な依存関係"""
    def checker(payload: dict = Depends(verify_token)):
        if payload.get("role") != required_role:
            raise HTTPException(status_code=403, detail="権限がありません")
        return payload
    return checker

@app.get("/admin")
def admin_only(user=Depends(require_role("admin"))):
    return {"message": f"ようこそ管理者 {user['sub']} さん!"}

@app.post("/logout")
def logout(token: str = Depends(oauth2_scheme)):
    """トークンをブラックリストに追加してログアウト"""
    blacklist.add(token)
    return {"message": "ログアウトしました"}

ここが重要です📌

  • ブラックリストをメモリ上のsetで管理しているので、本番環境ではRedisに置き換えが必要
  • RBACはFastAPIの Depends を使って「依存関係として注入」するパターンが主流
  • ライブラリが増えるほど、バージョン管理や互換性の維持コストも増える
  • FastAPI公式チュートリアルは現在 python-jose + passlib ではなく PyJWT + pwdlib[argon2] を使っている。python-joseはアルゴリズム混同の脆弱性(CVE-2024-33663)などが報告されているので、新規実装では公式と同じ構成を検討する

🆚 別解として話題のFitzという言語も知っておこう


今回話題になっているのが、Fitzです。ただし注意点があります。FitzはPythonのライブラリではなく、独自の構文を持つ別のプログラミング言語(Rustベース)で、HTTP・JWT・DB操作などが言語機能として最初から組み込まれています。つまり「FastAPIかFitzか」はPythonプロジェクト内で選べる2択ではなく、そもそも実装言語ごと変える話になる点は誤解しないようにしてください。

とはいえ「認証まわりを何個もライブラリを継ぎ足して実装する」やり方に対して、「最初から一つにまとまった言語・フレームワークを使う」という設計思想自体は、FastAPI流のエコシステム設計と対比する題材として面白い視点です。

📝 まとめ

JWT認証・RBAC・トークンブラックリストを組み合わせた本格的なAuth実装は、FastAPIだと複数ライブラリの連携が必要になりがちです。Fitzのように「言語ごと全部内包」を目指すアプローチも出てきていますが、既存のPythonプロジェクトに導入できるものではない点は押さえておきましょう。

まずはFastAPIで基本的な流れを手を動かして確認してみてください。「むずかしそう」を「できそう」に変える第一歩になるはずです💪 ぜひ試してみてください!

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

もしも

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

AIコーディングの現場活用法を学ぶ一冊

Amazonで見る

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

もしも

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

FastAPIでWebAPI開発を実践的に学ぶ

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。