0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FastAPIでGoogle OAuthを実装する方法

Last updated at Posted at 2025-02-25

🔹 概要

FastAPIを使用して,Google OAuth2.0を利用した認証方法を実装する.OAuth2.0を活用することによって,Googleアカウントを使ったログイン機能が可能となる.

🔹 主な手順

① Google CloudでクライアントIDを取得

② FastAPIのセットアップ

③ OAuth2の設定

④ エンドポイントの実装

①Google CloudでクライアントIDを取得

  1. Google Cloud Console にアクセスする

  2. 画面上部の 「プロジェクトの選択」 をクリックする

  3. 新しくプロジェクトを作成する

  4. 左側のメニューから 「APIとサービス」 → 「OAuth同意画面」 を選択する

    • 「Google Auth Platform はまだ構成されていません」 という表示に従い、プロジェクト構成を作成する
      OAuth同意画面の設定
  5. 左側のメニューから 「APIとサービス」 → 「認証情報」 を選択する

    • 画面上部の 「認証情報を作成」 → 「OAuth クライアント ID の作成」 を選択する
    • 「アプリケーションの種類」「ウェブアプリケーション」 を選択する
    • 「承認済みのリダイレクト URI」 に Google 認証後のリダイレクト先の URL を入力し、作成する
    • 作成後、クライアントIDクライアントシークレット が表示されるため、メモしておく
      クライアントIDとシークレット
  6. 左側のメニューから 「APIとサービス」 → 「OAuth同意画面」 → 「対象」 を選択し、テストするユーザーを追加する

②FastAPIのセットアップ

必要なパッケージのインストール

以下のコマンドを実行して,FastAPIとOAuth2認証に必要なパッケージをインストールする.

pip install fastapi google-auth Jinja2 httpx python-dotenv uvicorn

fastapi: Webフレームワーク
google-auth: Google 認証および OAuth2.0 に関連する認証処理を提供
Jinja2: テンプレートエンジン(HTMLのレンダリングに使用)
httpx: HTTPクライアント
python-dotenv: 環境変数の管理
uvicorn: 非同期ASGIサーバー

.envファイルの作成

プロジェクトのルートディレクトリに.envファイルを作成し,以下のようにGoogle OAuthのクライアント情報を設定する.

.env
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_REDIRECT_URI=your-google-redirect-url

your-google-client-id: OAuth クライアント ID の作成時に得たクライアントID
your-google-client-secret: OAuth クライアント ID の作成時に得たクライアントシークレット
your-google-redirect-url:OAuth クライアント ID の作成時に入力した承認済みのリダイレクト URI

③OAuth2の設定

Google OAuth2.0の認証情報を取得する

Google OAuth 2.0 認証に必要な設定を環境変数から取得し、定数として定義する.os.getenv関数を使用して,環境変数 GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET,および GOOGLE_REDIRECT_URI の値を先ほど作成した.envから取得する.

また,GOOGLE_AUTH_URLGOOGLE_TOKEN_URL,および GOOGLE_USER_INFO_URL は,Googleの認証,トークン取得,およびユーザ情報取得のためのエンドポイントURLを定義している.これにより、Google OAuth 2.0 認証フローを実装する際に必要な情報が一箇所にまとめられ,コードの可読性と保守性が向上する.

auth.py
import os
import httpx
from fastapi import APIRouter, Request, HTTPException
from fastapi.responses import RedirectResponse
from google.oauth2 import id_token
from google.auth.transport import requests
from fastapi.security import OAuth2AuthorizationCodeBearer
from twilio.rest import Client
from dotenv import load_dotenv

load_dotenv()

router = APIRouter(prefix="/auth", tags=["authentication"])

# Google OAuth2.0の設定
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REDIRECT_URI = os.getenv("GOOGLE_REDIRECT_URI")
GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth"
GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token"
GOOGLE_USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo"

ユーザーの認証とトークンの取得

OAuth2AuthorizationCodeBearerクラスのインスタンスを作成し,oauth2_schemeに代入している.このクラスは,OAuth2の認証コードフローを使用してベアラートークンを取得するための認証スキームを提供する.リクエストヘッダに含まれるベアラートークンを検証し,認証が成功した場合にトークンを返す.これにより,APIエンドポイントへのアクセス制御が可能になるのだ.具体的には,Google OAuth2.0の認証エンドポイントとトークンエンドポイントを使用することで,ユーザの認証とトークンの取得を行う.

authorizationUrltokenUrl の引数には,それぞれ GOOGLE_AUTH_URL と GOOGLE_TOKEN_URL が渡されている.これらのURLは,GoogleのOAuth2.0認証フローに必要なエンドポイントを指しており,GOOGLE_AUTH_URL はユーザが認証を行うためのURL,GOOGLE_TOKEN_URL は認証コードをトークンに交換するためのURLである.

auth.py
oauth2_scheme = OAuth2AuthorizationCodeBearer(
    authorizationUrl=GOOGLE_AUTH_URL,
    tokenUrl=GOOGLE_TOKEN_URL,
)

④エンドポイントの実装

Google OAuth 2.0認証のためのログインエンドポイントを定義

このエンドポイントにアクセスすると,login関数が非同期に実行される.login関数ではGoogleの認証URLを構築している.そして,RedirectResponseを使用して,ユーザをGoogleの認証ページにリダイレクトする.
RedirectResponseは,指定されたURLにリダイレクトするHTTPレスポンスを生成する.これにより,ユーザはGoogleの認証ページに移動し,認証を行うことが可能となる.認証が成功すると,指定されたリダイレクトURIに認証コードが返される.

auth.py
@router.get("/login")
async def login():
    google_auth_url = f"{GOOGLE_AUTH_URL}?client_id={GOOGLE_CLIENT_ID}&redirect_uri={GOOGLE_REDIRECT_URI}&response_type=code&scope=openid%20email&access_type=offline&prompt=consent"
    return RedirectResponse(google_auth_url)

Google OAuth 2.0 認証フローのコールバックエンドポイントを定義

ユーザがGoogleの認証ページで認証を行った後,Google認証コードをこのエンドポイントにリダイレクトする.このエンドポイントは,認証コードを受け取り,アクセストークンとIDトークンを取得するために使用される.

このエンドポイントにアクセスすると,callback関数が非同期に実行される.この関数の引数は,認証コードとリクエストオブジェクトである.認証コードはGoogleからリダイレクトされた際にクエリパラメータとして渡される.

次に,認証コードを使用してGoogleのトークンエンドポイントにPOSTリクエストを送信する.リクエストのデータには,認証コード,クライアントID,クライアントシークレット,リダイレクトURI,およびグラントタイプ(アクセス権の付与の方法)が含まれている.そして,httpx.AsyncClientを使用して非同期にリクエストを送信し,レスポンスを受け取る.レスポンスが成功したかどうかを確認し,成功した場合はレスポンスのJSONデータを取得する.

取得したトークンレスポンスからIDトークンを抽出し,IDトークンが存在しない場合はHTTP 400エラーを発生させる.IDトークンが存在する場合は,id_token.verify_oauth2_token関数を使用してトークンを検証し,ユーザ情報を取得する.ユーザーの名前をセッションに保存し,/v1/helloworldエンドポイントにリダイレクトする.

auth.py
@router.get("/callback")
async def callback(code: str, request: Request):
    data = {
        "code": code,
        "client_id": GOOGLE_CLIENT_ID,
        "client_secret": GOOGLE_CLIENT_SECRET,
        "redirect_uri": GOOGLE_REDIRECT_URI,
        "grant_type": "authorization_code",
    }
    async with httpx.AsyncClient() as client:
        response = await client.post(GOOGLE_TOKEN_URL, data=data)
        response.raise_for_status()
        token_response = response.json()
    
    id_token_value = token_response.get("id_token")
    if id_token_value is None:
        raise HTTPException(status_code=400, detail="id_tokenが取得できませんでした")
    
    try:
        id_info = id_token.verify_oauth2_token(id_token_value, requests.Request(), GOOGLE_CLIENT_ID)
        
        name = id_info.get("name")
        request.session["user_name"] = name
        
        return RedirectResponse(url="/v1/helloworld")
    
    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"id_tokenの検証に失敗しました: {str(e)}") 
    
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"エラーが発生しました: {str(e)}")

🔹 まとめ

・Google CloudでOAuth2.0のクライアントIDとシークレットを取得

・FastAPIをセットアップし,OAuth2の認証エンドポイントを作成

・Google認証のリダイレクトを処理し,ユーザ情報を取得

これにより,Googleアカウントでログインできるようになる.

🔹 参考文献

以下の文献を参考に実装を行いました.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?