StreamlitでGoogle OAuth2.0を使った認証を行う
概要
Streamlitは、Pythonで気軽にインタラクティブなウェブアプリケーションを作ることができるパッケージです。私自身も機械学習を使ったデモや可視化ツールとして積極的に活用していますが、そうやってStreamlitアプリを量産して適当にホストしていると、だんだん社内で利用する人が増えてきたり、社外の協力者に使ってもらうことを検討し始めたり……。
そして発生するのがアクセス制限と認証の問題です。特に外部IPで公開する場合は、URLを知っている人なら誰もがアクセスできる状態になってしまい、アプリケーションの内容によってはセキュリティ的に問題となります。私はこれまでStreamlitでid/passの入力ボックスを実装してみたり、GCE上で動いているnginxでBASIC認証を行うなどして制御してきたのですが、やはり個人でアカウント情報を管理するのは面倒かつ不安で、何かしらの基盤上で統一的に管理したほうが良さそうという結論になりました。
そこでこの記事では、Google OAuth2.0の認証基盤を使って、Streamlitアプリへのアクセス認証を行うための手順を紹介します。なお、手順や実装は以下の記事を参考にしています。
Implementing Google OAuth in Streamlit | by Duc Anh Bui | Towards Data Science
方法
今回はローカルに立てたStreamlitのアプリに、OAuth2のサインイン認証を付ける事例で説明します。GCEやCloud Run等にデプロイしている場合についても、基本的には方法は同じです。
- コード:yagays/streamlit-google-oauth: An example Streamlit application that incorporates Google OAuth 2.0
1. GCPでOAuth同意画面を作成する
まずはGCPでOAuthの認証を設定していきます。「APIとサービス」から「OAuth同意画面」に進み、同意画面を作成します。
OAuth 同意画面 – API とサービス – Google Cloud Platform
今回は組織内のユーザのみ利用する想定で「内部」を選択します。対象となるユーザの種類は後に段階的に変更することができるため、外部に公開する前提でもまずは内部で作成し、準備が整った段階で外部公開に変更するほうが良いと思います。
今回はサインインの認証のみを利用するため、スコープは特に設定しません。
2. GCPでOAuth2.0 クライアントIDを作成する
次に、OAuth2.0のクライアントIDを作成します。「APIとサービス」の「認証情報」から、画面上部の「認証情報を作成」の中の「OAuthクライアントID」を選択し、以下のように設定します。
認証情報 – API とサービス – Google Cloud Platform
- アプリケーションの種類:
ウェブ アプリケーション
- 名前:
(任意のアプリ名)
- 認証済みのリダイレクトURI:
http://localhost:8501
認証済みのリダイレクトURIは、StreamlitのアプリケーションのURLを設定します。今回はローカルで起動しているためlocalhostとしていますが、もしGCEやCloud RunなどでStreamlitアプリをホストしている場合は、そちらのURLを設定します。
クライアントIDとクライアントシークレットが発行されます。後でStreamlitに認証情報として設定するため、メモしておきます(後からでも確認することが可能です)。
3. Google People APIを有効にする
認証時に必要となるため、Google People APIを有効にしておきます。
これで認証の準備は整いました。
4. Streamlitで認証を実装する
Streamlitで認証を実装します。
import streamlit as st
from streamlit_google_oauth import google_oauth2_required
@google_oauth2_required
def main():
user_id = st.session_state.user_id
user_email = st.session_state.user_email
st.write(f"You're logged in {user_id}, {user_email}")
main()
Streamlitのapp.py
で実装するのは実質これだけです。main()
の中に今まで通りのStreamlitのアプリケーションを構築していくことができます。
認証に関しては@google_oauth2_required
というデコレーターの中で認証を行っています。streamlit_google_oauth.py
は、下記リンク先から取得してください。
streamlit-google-oauth/streamlit_google_oauth.py at main · yagays/streamlit-google-oauth
必要なパッケージは以下の2つです。
streamlit
httpx-oauth
Streamlitは、Version 0.84.0から導入されたSession Stateという機能を利用しているため、これより新しいバージョンを利用してください。
5. 認証情報等を環境変数にセットする
@google_oauth2_required
の中では、先ほどGCPで設定した値を環境変数から取得して利用します。そのため、下記の名前で環境変数を設定しておきます。
- クライアントID:
GOOGLE_CLIENT_ID
- クライアントシークレット:
GOOGLE_CLIENT_SECRET
- リダイレクトURI:
REDIRECT_URI
6. 実行する
設定はこれで完了です。最後に動作チェックをしてみて、正常に認証されるかを確認します。
export GOOGLE_CLIENT_ID="xxx"
export GOOGLE_CLIENT_SECRET="yyy"
export REDIRECT_URI="http://localhost:8501"
streamlit run app.py
無事に認証を通すことができました!
まとめ
この記事では、Streamlitのアプリケーションにアクセス認証を付与するためにGoogle OAuth2.0を利用した例を紹介しました。Streamlitでのアプリ実装に手を加える必要があるものの、比較的簡単に実装できてかつGCPの認証基盤を経由することができます。
Discussion
GCPでプロジェクト作成や、OAuth2.0 クライアントIDは料金はかかるのでしょうか?
ポートフォリオサイトで使用したいのですそれほどリクエスト回数は多くないとは思うのですが、「1ヶ月○回リクエストを読んだら料金が発生する」とかあればご教示いただきたいです。
すいません、料金体系に関しては私自身あまり良く把握しておらず、的確なアドバイスはできません。プロジェクト作成はおそらく料金がかかりませんが、認証に関してはアクティブユーザ数等によって料金がかかる場合があるようです(ヘビーな使い方をした場合のみのようですが)。
料金 | ID プラットフォーム | Google Cloud
Googleではないですが、別のOauth2実装をする際に参考にさせていただきました。tokenを保存しているのはsession_stateであるためブラウザリロードの度に再度認証(リンククリック)が必要という理解であっておりますでしょうか