LoginSignup
1
2

python(Flaskアプリ)からGoogle OAuthするための開発環境、本番環境の話

Last updated at Posted at 2023-06-01

いつも苦労するので備忘録として

pythonからGoogle OAuthする方法ですが、検索すると情報が古かったり、サービスアカウント使うやりかただったりして、個人のユーザーに対してサービス提供する為のやり方がいまいち分からなかったりしたのでまとめ。

必須事項

  • GCP使ってAPIキーを取得する
    • Google_Client_IDとGoogle_Client_Secretは必須です
  • redirect_uriは、帰ってくるURLを入れてください。これはGCPに設定したものと同じである必要があります

OAuthするためのURIを生成する

GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration"
)
def get_google_provider_cfg():
    return requests.get(GOOGLE_DISCOVERY_URL).json()
    
def get_google_request_url():
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]
    google_client = WebApplicationClient(os.environ.get("Google_Client_ID"))
    request_uri = google_client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri=os.environ.get("redirect_uri"),
        scope=['https://www.googleapis.com/auth/calendar.readonly','email','https://www.googleapis.com/auth/spreadsheets.readonly','https://www.googleapis.com/auth/documents.readonly','https://www.googleapis.com/auth/presentations.readonly'],
        approval_prompt='force',
        access_type="offline"
    )
    return request_uri

こんな感じでget_google_request_urlを使ってURLを作ってアクセスします

リダイレクト後の処理を書く

受け取った情報からトークンを取得する必要があります
ルートの設定(/google/callback)は、自分の環境に合わせて書き換えてください
ちなみに、この設定の場合はリダイレクトURLはこちらになります
http://localhost:5000/google/callback

@bolt.route("/google/callback", methods=["GET"])
def google_auth_callback(app_id):
    # Googleから返却された認証コードを取得する
    code = request.args.get("code")
        
    #トークンを取得するためのURLを取得する
    google_provider_cfg = get_google_provider_cfg()
    token_endpoint = google_provider_cfg["token_endpoint"]

    # トークンを取得するための情報を生成し、送信する
    google_client = WebApplicationClient(os.environ.get("Google_Client_ID"))
    token_url, headers, body = google_client.prepare_token_request(
        token_endpoint,
        authorization_response=request.url,
        redirect_url=request.base_url,
        code=code,
        approval_prompt='force',
        access_type='offline'
    )
    token_response = requests.post(
        token_url,
        headers=headers,
        data=body,
        auth=(os.environ.get("Google_Client_ID"), os.environ.get("Google_Client_Secret"),
    )
    google_access_token = token_response.json().get('access_token')
    google_refresh_token = token_response.json().get('refresh_token')

以上の処理でgoogle_access_tokenとgoogle_refresh_tokenがとれます
google_refresh_tokenは一度しか取れないので注意してください(開発時に何度も取得すると思うのですが、revokeしないとrefresh_tokenは付与されないのです)

ローカル実行時の注意

ローカルで実行する場合は環境変数に
export OAUTHLIB_INSECURE_TRANSPORT=1
これを設定してください。
これをやらないと
google_client.prepare_token_request
のところで、httpsじゃないと駄目ですよと怒られます。

逆に本番環境でこれを入れると、それはそれで怒られます。

1
2
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
1
2