> This page is for プラットフォーム, version V4 (default).
> For other versions, use one of these documentation indexes:
> - V4 (default): https://next.developer.frame.io/platform/v4/llms.txt
> - V4 Experimental: https://next.developer.frame.io/platform/v4-experimental/llms.txt
> - レガシー: https://next.developer.frame.io/platform/v2/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# Frame.io Python SDK — 認証ガイド

このガイドでは、**Frame.io Python SDK**（`frameio`）を使用してFrame.io APIで認証する方法について説明します。Frame.io V4 APIは[Adobe Identity Management Service（IMS）](https://developer.adobe.com/developer-console/docs/guides/authentication/)、アドビの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](https://adminconsole.adobe.com/)を介して管理されているFrame.io V4アカウントでのみ利用可能です。

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

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

---

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

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

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

> **Info**
>
> 詳細については、[Frame.io サーバー間サポートを使用した設定の自動化](https://helpx.adobe.com/jp/enterprise/using/automate-using-frame-io.html)を参照してください。

---

## クイックスタート

### 前提条件

1. **Adobe Developer Console**からの[資格情報](https://developer.adobe.com/console)：
   * **Client ID** — すべてのOAuthフローに必要
   * **Client Secret** — Server-to-ServerおよびWeb Appフローに必要
   * **Redirect URI** — Web AppおよびSPAフローに必要。Adobeプロジェクトに登録する必要があります

2. **SDKをインストール：**

```bash
pip install frameio
```

### 方法の選択

* **ユーザーが関与しない場合：** **Server-to-Server**（`ServerToServerAuth`）を使用します。
* **ユーザーが関与し、シークレットを保存できる場合：** **Web App**（`WebAppAuth`）を使用します。
* **ユーザーが関与するが、シークレットを保存できない場合：** **SPA**（`SPAAuth`）を使用します。

---

## アクセストークン

既にアクセストークンがある場合（他のOAuthシステムまたは以前の交換から、例えば[API Explorer](/platform/api-reference/accounts/index?explorer=true)経由）、直接渡すことができます：

```python
from frameio import Frameio

client = Frameio(token="YOUR_ACCESS_TOKEN")
```

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

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

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

```python
from frameio import Frameio

client = Frameio(
    token="YOUR_LEGACY_DEVELOPER_TOKEN",
    headers={"x-frameio-legacy-token-auth": "true"},
)
```

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

---

## サーバー間（クライアント資格情報）

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

#### 同期

```python
from frameio import Frameio
from frameio.auth import ServerToServerAuth

auth = ServerToServerAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
)

client = Frameio(token=auth.get_token)
```

#### 非同期

```python
from frameio import AsyncFrameio
from frameio.auth import AsyncServerToServerAuth

auth = AsyncServerToServerAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
)

client = AsyncFrameio(token=auth.get_token)
```

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

### 仕組み

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

内部的には：

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

### 明示的認証

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

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

---

## Web App（認証コード）

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

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

#### 同期

```python
from frameio.auth import WebAppAuth

auth = WebAppAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
    redirect_uri="https://yourapp.com/callback",
)

# CSRF攻撃を防ぐために暗号学的にランダムなstate値を生成
import secrets
state = secrets.token_urlsafe(32)

authorization_url = auth.get_authorization_url(state=state)
# `state`をユーザーのセッションに保存し、`authorization_url`にリダイレクトします
```

#### 非同期

```python
from frameio.auth import AsyncWebAppAuth

auth = AsyncWebAppAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
    redirect_uri="https://yourapp.com/callback",
)

# get_authorization_url は同期的です（I/O は不要）
import secrets
state = secrets.token_urlsafe(32)

authorization_url = auth.get_authorization_url(state=state)
```

#### コールバックを処理する

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

#### 同期

```python
# コールバックハンドラ内で（例：Flask/FastAPIルート）：
auth.exchange_code(code=request.args["code"])
```

#### 非同期

```python
# 非同期コールバックハンドラ内で（例：FastAPIルート）：
await auth.exchange_code(code=request.query_params["code"])
```

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

#### クライアントを使用する

#### 同期

```python
from frameio import Frameio

client = Frameio(token=auth.get_token)
```

#### 非同期

```python
from frameio import AsyncFrameio

client = AsyncFrameio(token=auth.get_token)
```

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

### 完全なFlaskの例

```python
import secrets
from flask import Flask, redirect, request, session
from frameio import Frameio
from frameio.auth import WebAppAuth

app = Flask(__name__)
app.secret_key = secrets.token_bytes(32)

auth = WebAppAuth(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
    redirect_uri="http://localhost:5000/callback",
)

@app.route("/login")
def login():
    state = secrets.token_urlsafe(32)
    session["oauth_state"] = state
    return redirect(auth.get_authorization_url(state=state))

@app.route("/callback")
def callback():
    if request.args.get("state") != session.pop("oauth_state", None):
        return "Invalid state parameter", 403

    auth.exchange_code(code=request.args["code"])

    client = Frameio(token=auth.get_token)
    accounts = client.accounts.index()
    return f"Authenticated — {len(accounts.data)} account(s) accessible."
```

---

## 単一ページアプリ / PKCE（認証コード + PKCE）

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

#### 認証URLを生成する

#### 同期

```python
from frameio.auth import SPAAuth

auth = SPAAuth(
    client_id="YOUR_CLIENT_ID",
    redirect_uri="https://yourapp.com/callback",
)

import secrets
state = secrets.token_urlsafe(32)

result = auth.get_authorization_url(state=state)
# result.url            -> ユーザーをここにリダイレクト
# result.code_verifier  -> コールバックまで安全に保存
```

#### 非同期

```python
from frameio.auth import AsyncSPAAuth

auth = AsyncSPAAuth(
    client_id="YOUR_CLIENT_ID",
    redirect_uri="https://yourapp.com/callback",
)

# get_authorization_url は同期的です（I/O は不要）
import secrets
state = secrets.token_urlsafe(32)

result = auth.get_authorization_url(state=state)
```

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

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

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

#### 同期

```python
auth.exchange_code(
    code="CODE_FROM_CALLBACK",
    code_verifier=result.code_verifier,
)
```

#### 非同期

```python
await auth.exchange_code(
    code="CODE_FROM_CALLBACK",
    code_verifier=result.code_verifier,
)
```

#### クライアントを使用する

#### 同期

```python
from frameio import Frameio

client = Frameio(token=auth.get_token)
```

#### 非同期

```python
from frameio import AsyncFrameio

client = AsyncFrameio(token=auth.get_token)
```

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

---

## 非同期使用法

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

| 同期                   | 非同期                       |
| -------------------- | ------------------------- |
| `ServerToServerAuth` | `AsyncServerToServerAuth` |
| `WebAppAuth`         | `AsyncWebAppAuth`         |
| `SPAAuth`            | `AsyncSPAAuth`            |

APIは同一です。`get_authorization_url`は同期のまま（I/Oなし）ですが、`exchange_code`、`refresh`、`revoke`、`get_token`はすべて`async`です。非同期クラスは`AsyncFrameio`と一緒に使用してください。

### 手動トークン更新

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

#### 同期

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

#### 非同期

```python
await auth.refresh()
```

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

---

## トークンの永続化

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

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

```python
# exchange_code()の後、トークン状態を保存
token_data = auth.export_tokens()
# token_dataは辞書です：{"access_token": "...", "refresh_token": "...", "expires_at": 1234567890.0}
# データベース、ファイル、またはシークレットストアに保存

# 次回の起動時に復元
auth.import_tokens(token_data)
client = Frameio(token=auth.get_token)
# SDKはトークンの有効期限が近い場合、自動的にリフレッシュします
```

### `on_token_refreshed`による自動永続化

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

```python
import json
from pathlib import Path

TOKEN_FILE = Path("tokens.json")

def save_tokens(tokens: dict):
    TOKEN_FILE.write_text(json.dumps(tokens))

auth = WebAppAuth(
    client_id="...",
    client_secret="...",
    redirect_uri="...",
    on_token_refreshed=save_tokens,
)

# 起動時に、利用可能な場合は復元
if TOKEN_FILE.exists():
    auth.import_tokens(json.loads(TOKEN_FILE.read_text()))
```

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

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

---

## トークンの取り消し

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

```python
auth.revoke()
```

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

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

---

## エラー処理

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

```python
from frameio.auth import (
    FrameioAuthError,
    AuthenticationError,
    TokenExpiredError,
    ConfigurationError,
    NetworkError,
    RateLimitError,
)

try:
    auth.exchange_code(code="...")
except TokenExpiredError:
    # リフレッシュトークンの有効期限が切れています。ユーザーを再度サインインにリダイレクトしてください
    pass
except AuthenticationError as e:
    # トークン交換に失敗しました
    print(f"Error: {e.error_code} - {e.error_description}")
except NetworkError:
    # タイムアウトまたは接続失敗（再試行後）
    pass
except RateLimitError as e:
    # Adobe IMSから429。e.retry_after秒後に再試行してください
    pass
except FrameioAuthError:
    # その他の認証エラーのキャッチオール
    pass
```

### エラーリファレンス

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

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

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

```python
from frameio.auth import TokenExpiredError

try:
    client = Frameio(token=auth.get_token)
    assets = client.files.list(project_id="...")
except TokenExpiredError:
    # 永続化されたトークンをクリアし、ユーザーをログインにリダイレクト
    auth.revoke()
    return redirect("/login")
```

---

## 設定リファレンス

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

#### パラメータリファレンス

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

### ステージング環境

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

```python
auth = ServerToServerAuth(
    client_id="...",
    client_secret="...",
    ims_base_url="https://ims-na1-stg1.adobelogin.com",
)
```

### カスタムHTTPクライアント

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

```python
import httpx

http_client = httpx.Client(
    proxy="http://corporate-proxy:8080",
    verify="/path/to/custom-ca-bundle.pem",
)

auth = ServerToServerAuth(
    client_id="...",
    client_secret="...",
    http_client=http_client,
)
```

---

## スレッドセーフティ

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

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