Frame.io Python SDK — 認証ガイド

このガイドでは、Frame.io Python SDKframeio)を使用してFrame.io APIで認証する方法について説明します。Frame.io V4 APIはAdobe Identity Management Service(IMS)、アドビのOAuth 2.0アイデンティティプラットフォームを使用します。

これはPython開発者向けの独立したリファレンスです。以下のすべてのコード例とフローはframeioパッケージのみを対象としています。


Python SDKにおける認証タイプ

Python SDKは4つの認証オプションをサポートしています:

方式ユースケースユーザー操作?クライアントシークレットが必要?
静的トークンクイックスクリプト、テスト、または既にトークンを持っている場合いいえいいえ
Server-to-Serverバックエンドサービス、cronジョブ、自動化いいえはい
Web Appサーバーサイドアプリ(Flask、Django、FastAPI)はいはい
SPA (PKCE)ブラウザーアプリ、CLI、またはシークレットを保存できないアプリはいいいえ

Server-to-Serverはアプリをユーザー操作なしでサービスアカウントとして動作させます。これはAdobe Admin Consoleを介して管理されているFrame.io V4アカウントでのみ利用可能です。

Web AppSPAはアプリを特定のユーザーとして動作させます。どちらも内部的にAdobe IMSを使用します。ユーザーがアプリを認可し、SDKがその結果のコードをトークンと交換します。Python SDKはIMSの/authorize/v2および/token/v3フローを処理します。Web Appではクライアントシークレットが必要で、SPAでは代わりにPKCEを使用します。

Adobeのネイティブアプリ資格情報はOSレベルでリダイレクトをインターセプトするカスタムURIスキームハンドラー(例:adobe+<hash>://…)を必要とします。Pythonにはそのようなハンドラーを登録する標準的な方法がないため、Python SDKはNativeAppAuthクラスを提供しません。ユーザー対話型のPythonアプリには、ローカルコールバックサーバー(例:FlaskやFastAPI)と共にWebAppAuthを使用してください。非対話型のワークロードにはServerToServerAuthを使用してください。


サービスアカウントユーザー

Server-to-Server認証を使用する場合、アプリケーションはサービスアカウントユーザーとして動作します。これは、サービスに代わってアクションを実行できる独特なアカウントタイプです。これらはFrame.ioの他のユーザーに表示されます。サービスアカウントがアクションを実行すると、その名前がUIに表示されます。

Adobe Admin ConsoleDeveloper Consoleを通じてサービスアカウントアクセスを許可および取り消すことができます。サービスアカウント名はFrame.io UIから管理されます。デフォルトでは、最初のS2S接続はService Account User、2番目はService Account User 2などと名付けられます。

詳細については、Frame.io サーバー間サポートを使用した設定の自動化を参照してください。


クイックスタート

前提条件

  1. Adobe Developer Consoleからの資格情報

    • Client ID — すべてのOAuthフローに必要
    • Client Secret — Server-to-ServerおよびWeb Appフローに必要
    • Redirect URI — Web AppおよびSPAフローに必要。Adobeプロジェクトに登録する必要があります
  2. SDKをインストール:

$pip install frameio

方法の選択

  • ユーザーが関与しない場合: Server-to-ServerServerToServerAuth)を使用します。
  • ユーザーが関与し、シークレットを保存できる場合: Web AppWebAppAuth)を使用します。
  • ユーザーが関与するが、シークレットを保存できない場合: SPASPAAuth)を使用します。

アクセストークン

既にアクセストークンがある場合(他のOAuthシステムまたは以前の交換から、例えばAPI Explorer経由)、直接渡すことができます:

1from frameio import Frameio
2
3client = Frameio(token="YOUR_ACCESS_TOKEN")

これは最もシンプルなアプローチですが、トークンは最終的に期限切れになり、SDKは自動的に更新しません。

レガシーデベロッパートークン

Adobe Admin Consoleでまだ管理されていないV4移行アカウントの場合、Frame.ioデベロッパーサイトからのレガシーデベロッパートークンを引き続き使用できます。x-frameio-legacy-token-authヘッダーを含めてtrueに設定する必要があります:

1from frameio import Frameio
2
3client = Frameio(
4 token="YOUR_LEGACY_DEVELOPER_TOKEN",
5 headers={"x-frameio-legacy-token-auth": "true"},
6)

レガシーデベロッパートークンは期限切れになりませんが、移行メカニズムです。新しい統合と本番ワークロードには、以下のOAuth 2.0フローのいずれかを使用することをお勧めします。詳細については、移行ガイドを参照してください。


サーバー間(クライアント資格情報)

ユーザーの操作なしにFrame.ioアクセスが必要なバックエンドサービスやスクリプトに使用します。このフローはAdobe Admin Consoleを介して管理されているFrame.io V4アカウントでのみ利用可能です。アプリケーションは、人間のループなしでサービスアカウントユーザーとして認証されます。

1from frameio import Frameio
2from frameio.auth import ServerToServerAuth
3
4auth = ServerToServerAuth(
5 client_id="YOUR_CLIENT_ID",
6 client_secret="YOUR_CLIENT_SECRET",
7)
8
9client = Frameio(token=auth.get_token)

これだけです。auth.get_tokenは、SDKがすべてのリクエストで呼び出すコール可能オブジェクトです。現在のトークンがまだ有効な場合、すぐに戻ります。期限切れが近い場合、完全に透過的に新しいトークンを最初に取得します。

仕組み

クライアント資格情報(クライアントID + シークレット)は期限切れになりません。セキュリティ衛生のために手動でのみローテーションします。S2Sは、手動介入なしで効果的に永続的で中断のないAPIアクセスを提供します。

内部的には:

  1. 最初のAPI呼び出しで、get_tokenclient_credentials付与を使用してAdobe IMSから新しいアクセストークンをリクエストします。
  2. トークンはメモリにキャッシュされます。個々のアクセストークンは期限切れになりますが(通常24時間)、これは自動的に処理されます。
  3. キャッシュされたトークンが更新バッファー内にある場合(デフォルト:期限切れの60秒前)、SDKは同じクライアント資格情報を使用して自動的に新しいトークンを取得します。
  4. リフレッシュトークンは関与しません。クライアント資格情報自体が長期間有効なシークレットであり、常に新しいアクセストークンの作成に使用できます。

明示的認証

トークンを積極的に取得したい場合(例えば、起動時に不正な資格情報で高速に失敗させるため):

1auth = ServerToServerAuth(client_id="...", client_secret="...")
2auth.authenticate() # raises AuthenticationError if credentials are invalid
3client = Frameio(token=auth.get_token)

Web App(認証コード)

ユーザーがAdobe IDでサインインするサーバーサイドアプリケーションに使用します。このフローではクライアントシークレットが必要で、サーバー上に安全に保存する必要があります。

1

ユーザーをAdobe IMSにリダイレクトする

1from frameio.auth import WebAppAuth
2
3auth = WebAppAuth(
4 client_id="YOUR_CLIENT_ID",
5 client_secret="YOUR_CLIENT_SECRET",
6 redirect_uri="https://yourapp.com/callback",
7)
8
9# CSRF攻撃を防ぐために暗号学的にランダムなstate値を生成
10import secrets
11state = secrets.token_urlsafe(32)
12
13authorization_url = auth.get_authorization_url(state=state)
14# `state`をユーザーのセッションに保存し、`authorization_url`にリダイレクトします
2

コールバックを処理する

Adobe IMSがユーザーをredirect_uriにリダイレクトして戻すとき、codestateパラメータを抽出します。stateが保存したものと一致することを確認してから、コードをトークンと交換します:

1# コールバックハンドラ内で(例:Flask/FastAPIルート):
2auth.exchange_code(code=request.args["code"])

これにより、認証コードがアクセストークンとリフレッシュトークンに交換され、両方が内部に保存されます。

3

クライアントを使用する

1from frameio import Frameio
2
3client = Frameio(token=auth.get_token)

これだけです。これ以降、get_tokenがトークンのライフサイクルを自動的に管理します。アクセストークンの有効期限が近づくと、SDKはリフレッシュトークンを使用して新しいトークンを取得します。ユーザーの操作は必要ありません。

完全なFlaskの例

1import secrets
2from flask import Flask, redirect, request, session
3from frameio import Frameio
4from frameio.auth import WebAppAuth
5
6app = Flask(__name__)
7app.secret_key = secrets.token_bytes(32)
8
9auth = WebAppAuth(
10 client_id="YOUR_CLIENT_ID",
11 client_secret="YOUR_CLIENT_SECRET",
12 redirect_uri="http://localhost:5000/callback",
13)
14
15@app.route("/login")
16def login():
17 state = secrets.token_urlsafe(32)
18 session["oauth_state"] = state
19 return redirect(auth.get_authorization_url(state=state))
20
21@app.route("/callback")
22def callback():
23 if request.args.get("state") != session.pop("oauth_state", None):
24 return "Invalid state parameter", 403
25
26 auth.exchange_code(code=request.args["code"])
27
28 client = Frameio(token=auth.get_token)
29 accounts = client.accounts.index()
30 return f"Authenticated — {len(accounts.data)} account(s) accessible."

単一ページアプリ / PKCE(認証コード + PKCE)

ブラウザーベースのアプリケーション、デスクトップアプリ、またはクライアントシークレットを安全に保存できないCLIツールに使用します。このフローはPKCE (RFC 7636)を使用して認証コード交換を保護します。

1

認証URLを生成する

1from frameio.auth import SPAAuth
2
3auth = SPAAuth(
4 client_id="YOUR_CLIENT_ID",
5 redirect_uri="https://yourapp.com/callback",
6)
7
8import secrets
9state = secrets.token_urlsafe(32)
10
11result = auth.get_authorization_url(state=state)
12# result.url -> ユーザーをここにリダイレクト
13# result.code_verifier -> コールバックまで安全に保存

get_authorization_urlは、完全なURL(PKCEのcode_challengeが埋め込まれた)と次のステップで必要なcode_verifierを含むAuthorizationUrlResultを返します。

2

ベリファイアと共にコードを交換する

ユーザーがリダイレクトされて戻ってきたとき:

1auth.exchange_code(
2 code="CODE_FROM_CALLBACK",
3 code_verifier=result.code_verifier,
4)
3

クライアントを使用する

1from frameio import Frameio
2
3client = Frameio(token=auth.get_token)

これだけです。更新はWebアプリと同じように動作します。SDKは自動的にリフレッシュトークンを使用します。違いは、SPAフローがパブリッククライアント用に設計されているため、更新時にクライアントシークレットが送信されないことです。


非同期使用法

すべての認証クラスには、Asyncが接頭辞として付いた非同期対応版があります。上記のコード例には、該当する場合にSyncAsyncのタブが含まれています。

同期非同期
ServerToServerAuthAsyncServerToServerAuth
WebAppAuthAsyncWebAppAuth
SPAAuthAsyncSPAAuth

APIは同一です。get_authorization_urlは同期のまま(I/Oなし)ですが、exchange_coderefreshrevokeget_tokenはすべてasyncです。非同期クラスはAsyncFrameioと一緒に使用してください。

手動トークン更新

WebアプリとSPAフローの場合、SDKはget_tokenを介してトークンを自動的に更新します。明示的なコントロールが必要な場合は、refresh()を直接呼び出すことができます:

1auth.refresh() # リフレッシュトークンを使用して新しいアクセストークンを取得

これは、自動リフレッシュバッファーに依存するのではなく、重要な操作の前に強制的にリフレッシュを実行したい場合に便利です。


トークンの永続化

すべての認証クラスは、再起動間でのトークン状態の永続化のためにexport_tokens()import_tokens()をサポートしています。WebアプリとSPAフローでは、アクセストークンとリフレッシュトークンがデフォルトでメモリに保存されるため、これは特に重要です。アプリケーションが再起動した場合、永続化しない限りユーザーは再認証が必要になります。サーバー間通信では、永続化はオプションです(クライアント資格情報は常に新しいトークンを生成できます)が、キャッシュされたトークンをインポートすることで起動時の余分なラウンドトリップを回避できます。

エクスポートとインポート

1# exchange_code()の後、トークン状態を保存
2token_data = auth.export_tokens()
3# token_dataは辞書です:{"access_token": "...", "refresh_token": "...", "expires_at": 1234567890.0}
4# データベース、ファイル、またはシークレットストアに保存
5
6# 次回の起動時に復元
7auth.import_tokens(token_data)
8client = Frameio(token=auth.get_token)
9# SDKはトークンの有効期限が近い場合、自動的にリフレッシュします

on_token_refreshedによる自動永続化

トークンが更新されるたびに自動的に永続化するには、on_token_refreshedコールバックを使用します:

1import json
2from pathlib import Path
3
4TOKEN_FILE = Path("tokens.json")
5
6def save_tokens(tokens: dict):
7 TOKEN_FILE.write_text(json.dumps(tokens))
8
9auth = WebAppAuth(
10 client_id="...",
11 client_secret="...",
12 redirect_uri="...",
13 on_token_refreshed=save_tokens,
14)
15
16# 起動時に、利用可能な場合は復元
17if TOKEN_FILE.exists():
18 auth.import_tokens(json.loads(TOKEN_FILE.read_text()))

コールバックはexport_tokens()と同じ辞書形式を受け取り、トークンの更新が成功するたびに実行されます。

非同期クラスの場合、on_token_refreshedは通常の関数またはasync関数のいずれかを使用できます。両方がサポートされています。


トークンの取り消し

ユーザーをサインアウトし、Adobe IMSでトークンを無効にするには:

1auth.revoke()

これにより、アクセストークンとリフレッシュトークンの両方についてAdobe IMSに対してベストエフォートの取り消しリクエストが行われ、その後すべてのローカルトークン状態がクリアされます。取り消し後、ユーザーは再認証する必要があります。

非同期クラスの場合は、await auth.revoke()を使用します。


エラー処理

すべての認証エラーはFrameioAuthErrorから継承されるため、広範囲にキャッチするか、特定のケースを処理できます:

1from frameio.auth import (
2 FrameioAuthError,
3 AuthenticationError,
4 TokenExpiredError,
5 ConfigurationError,
6 NetworkError,
7 RateLimitError,
8)
9
10try:
11 auth.exchange_code(code="...")
12except TokenExpiredError:
13 # リフレッシュトークンの有効期限が切れています。ユーザーを再度サインインにリダイレクトしてください
14 pass
15except AuthenticationError as e:
16 # トークン交換に失敗しました
17 print(f"Error: {e.error_code} - {e.error_description}")
18except NetworkError:
19 # タイムアウトまたは接続失敗(再試行後)
20 pass
21except RateLimitError as e:
22 # Adobe IMSから429。e.retry_after秒後に再試行してください
23 pass
24except FrameioAuthError:
25 # その他の認証エラーのキャッチオール
26 pass

エラーリファレンス

例外発生するタイミング
ConfigurationError設定が不足または無効(例:空のclient_id、非HTTPSリダイレクトURI)
AuthenticationErrorトークン交換またはリフレッシュがAdobe IMSによって却下された(.error_code.error_descriptionを持つ)
TokenExpiredErrorリフレッシュトークン自体が期限切れ。ユーザーは再認証が必要
NetworkErrorすべての再試行後のHTTPタイムアウトまたは接続失敗
RateLimitErrorAdobe IMSが429を返した。バックオフガイダンスについては.retry_afterを確認
PKCEErrorPKCE検証が失敗(SPAフロー)

本番環境での期限切れリフレッシュトークンの処理

WebアプリとSPAフローでは、リフレッシュトークンは最終的に期限切れになります。その場合、get_tokenTokenExpiredErrorを発生させます。これをキャッチして、ユーザーを再度認証フローにリダイレクトする必要があります。

1from frameio.auth import TokenExpiredError
2
3try:
4 client = Frameio(token=auth.get_token)
5 assets = client.files.list(project_id="...")
6except TokenExpiredError:
7 # 永続化されたトークンをクリアし、ユーザーをログインにリダイレクト
8 auth.revoke()
9 return redirect("/login")

設定リファレンス

すべての認証クラスは、これらのオプションパラメータを受け入れます:

パラメータデフォルト説明
scopesフロー固有のデフォルトスペース区切りのOAuthスコープ。S2Sのデフォルトはopenid AdobeID frame.s2s.all;ユーザー向けフローのデフォルトはopenid email profile offline_access additional_info.roles
ims_base_urlhttps://ims-na1.adobelogin.comAdobe IMSベースURL。ステージングまたは非本番環境での上書き。
http_clientNoneプロキシ、mTLS、または接続プーリング用のカスタムhttpx.Client(またはhttpx.AsyncClient)。
timeout30トークンエンドポイント呼び出しのHTTPリクエストタイムアウト(秒)。
max_retries2一時的な障害(5xx、タイムアウト)の最大再試行回数。レート制限再試行(429)は別途トラッキングされます。
refresh_buffer60トークン有効期限前の積極的な更新をトリガーする秒数。
on_token_refreshedNoneトークンの更新が成功するたびに実行されるコールバック。access_tokenrefresh_tokenexpires_atを含む辞書を受け取ります。

ステージング環境

ims_base_urlを上書きしてステージングのAdobe IMSインスタンスを指定します。SDKはDEFAULT_IMS_BASE_URLhttps://ims-na1.adobelogin.com)もエクスポートするため、プログラムで本番環境の値を参照する必要がある場合に使用できます。

1auth = ServerToServerAuth(
2 client_id="...",
3 client_secret="...",
4 ims_base_url="https://ims-na1-stg1.adobelogin.com",
5)

カスタムHTTPクライアント

プロキシサポートやカスタムTLS設定の場合:

1import httpx
2
3http_client = httpx.Client(
4 proxy="http://corporate-proxy:8080",
5 verify="/path/to/custom-ca-bundle.pem",
6)
7
8auth = ServerToServerAuth(
9 client_id="...",
10 client_secret="...",
11 http_client=http_client,
12)

スレッドセーフティ

同期認証クラスは完全にスレッドセーフです。複数のスレッドが同時にget_tokenを呼び出し、更新が必要な場合、1つのスレッドのみが更新を実行します。他のスレッドは待機し、同じ結果を受け取ります。外部ロックは必要ありません。

非同期クラスはasyncio.Lockを使用して同じ保証を提供し、単一のイベントループ内の並行コルーチンに対して安全です。