方法:承認(アプリケーション)

はじめに

このガイドでは、Frame.io プロジェクトで **C2C アプリケーションを認証および承認する方法について説明します。

必要なもの

C2C の実装:セットアップガイドをまだ読んでいない場合は、目を通してから先へ進んでください。

また、統合の識別用に、当社チームから client_id を受け取っているはずです。client_id を受け取っていない場合は、C2C エコシステムに関するこちらの概要を参照し、当社チームにお問い合わせください。

client_id ではなく client_secret を受け取った場合は、C2C アプリケーションではなくハードウェアデバイスとしてセットアップされています。ハードウェアデバイスの認証ガイドに従うか、代わりに client_id を発行するために当社チームにお問い合わせください。

アプリケーション承認フローの詳細

実装する承認フローで予期されるユーザーエクスペリエンスについて、概要を理解していることを確認しましょう。以下のリソースをチェックして、このフローをユーザー目線で確認してください。Zoelog をダウンロードして Frame.io にログインし、C2C アプリケーションの承認プロセスを体験してみてください。

OAuth の概要

C2C アプリケーションは、認証と承認に OAuth 2.0 フローを使用します。これは標準化された呼び出しのセットで、サービスに対するサードパーティアプリケーションやユーザーの認証と承認に使用できます。OAuth フローの詳細については、こちらを参照してください。

コールバック/リダイレクト URI

サーバーは OAuth フローの一環として、お客様側が管理する URI/URL への HTTP 呼び出しを行う必要があります。ユーザーがブラウザーで Frame.io にログインすると、ブラウザーがこの URI にリダイレクトされ、アプリに情報が提供されます。リダイレクト URI には次の要件があります。

  • お客様が所有
  • 静的

この 2 つの条件を満たしている限り、デバイスに有効なリダイレクトを複数登録できます。

OAuth フロー中、Frame.io では、アプリケーションからリクエストされているコールバック URI が、こちらのファイルにある URI の 1 つであることを確認します。そうではなかった場合、承認フローは失敗します。このチェックを行わなかった場合、脅威アクターが自分たちの掌握しているアドレスへのリダイレクトを提供する可能性があります。

Frame.io では、開発目的で http://localhost への非 HTTPS コールバックをサポートしています。

デバイスの識別

Camera to Cloud に接続する場合、各アプリのインストールは、ユーザーのプロジェクトでデバイス接続をリストできるようにするために、一意に識別される必要があります。

C2C アプリケーションの場合、この識別子はデバイスの device_id です。実装をセットアップする際には、識別子をどのように付与するかを検討する必要があります。一部のプラットフォームでは、まさにこのユースケース向けに、デバイス + アプリに固有の識別子を生成するための API が提供されています。

プラットフォーム識別子
iOSIdentifierForVendor
AndroidFID または GUID
個人を特定できる情報を漏洩しないように注意してください

例えば、ユーザーのメールアドレスは、device_id としての使用に適した値ではありません。同様に、一意の識別子をソフトウェアが所有していることを確認してください。デバイスの MAC アドレスなどは使用しないでください。MAC アドレスはソフトウェアの所有ではないうえ、個人を特定できる情報と見なされる場合もあります。

使用する値に確信が持てない場合は、この選択について当社と協議し、統合ができるだけ簡単になる適切な値を選択することができます。

手順 1:ユーザーを認証する

YourApp™ **で Frame.io に接続する場合、Frame.io の設定セクションに移動し、「プロジェクトに接続」(または同様のもの)を選択します。このボタンを押すと、アプリへのログインと承認のために Frame.io にリダイレクトされます。

これを行うため、URL を作成し、web ブラウザーで開きます。Python 風疑似コードを見てみましょう。

Python
1def redirect_to_auth(config):
2 credentials = {
3 "response_type": "code",
4 "redirect_uri": "http://MyApp.io/frameio-callback",
5 "client_id": f"{MYAPP.client_id}",
6 "scope": "offline device.connect asset.create",
7 "state": str(uuid.uuid4()),
8 "device_id": f"{HARDWARE.get_vendor_id('com.mycompany.myapp')}",
9 }
10
11 encoded = parse.urlencode(credentials)
12 url = "https://applications.frame.io/oauth2/auth?" + encoded
13
14 webbrowser.open(url)

ここでの「ペイロード」は URL 自体にエンコードされており、完全にエンコードされた URL は次のようになります。

https://applications.frame.io/oauth2/auth?response_type=code&redirect_uri=http%3A%2F%2FMyApp.io%2Fframeio-callback&client_id=[client_id]&scope=offline+device.connect+asset.create&state=[state]&device_id=62f88d2a-1ae1-45e7-a6a0-81954e0cf2ff

これらのオプションを少し詳しく見ていきましょう。

response_type:OAuth フローでのレスポンスに使用する必要があるもの。この値は常に「code」であることが必要です。 これは OAuth サーバーに対して、リダイレクト URI にコードを送り返すよう指示します。リダイレクト URI は、実際の承認トークンの取得に使用されます。

redirect_uri:承認リクエストへの応答時に OAuth サーバーによる GET 対象となる URL/URI。

client_id:アプリを識別します。アプリケーション統合の場合、この値は Frame.io によって提供されます。

scope:アプリがリクエストしている権限のスペース区切りリスト。C2C アプリケーションでは次の権限を使用できます

  • offline:アプリは、初期トークンの有効期限が切れた際に独自の承認を更新できます。
  • device.connect:デバイスは、ユーザーが C2C 接続に使用できるアカウントとプロジェクトのリストを取得できます。
  • asset.create:アプリは、接続されているプロジェクトにアセットをアップロードできます。

これらのスコープの一部をリクエストして取得することは可能ですが、必ず 3 つすべてのスコープをリクエストするようにしてください。

state:このリクエストに関連付けられたランダムな値。state は、リダイレクト URI の呼び出しが有効なリクエストであることを確認するために使用されます。

登録した URI でコールバックを受信したら、state が予期されたものかどうかを検証する必要があります。

state はランダムである必要があります

state パラメーターがランダムでないと、CRSF 攻撃にさらされます。CRSF 攻撃では、攻撃者が state パラメーターをスプーフィングし、コールバックに不正なリクエストを送信します。state パラメーターの詳細については、Auth0 のブログを参照してください

device_id:この特定のデバイス/インストールの一意の識別子。デバイス ID **は、お客様が所有する値である(MAC **アドレス/CPU シリアル番号などではない)ことが必要で、個人を特定できる情報が含まれていてはいけません(メールアドレス、社会保障コード、サムプリントハッシュなどは含めないでください)。詳細については、device_id に関する前述のセクションを参照してください。

手順 2:OAuth レスポンスを受信する

ユーザーが Frame.io にログインし、リクエストされたスコープをブラウザーで受け入れた後、コールバック URI への GET リクエストが実行されます。リクエストには URL エンコードされたペイロードが含まれており、次のクエリパラメーターがあります。

code:Frame.io のバックエンドから実際の承認トークンを取得するために使用されるコード。

state:手順 1 で元の承認リクエストに含まれていた状態値。

scope:付与されるスコープ/権限。

フル URI は次のようになります。

https://MyApp.io/frameio-callback?code=[authorization_code]&scope=offline+device.connect+asset.create&state=[state]

URI の解析は難しい場合がありますが、HTTP/サーバーライブラリにはそのための優れたリソースがあることが多いので、この値の解析を試みる前に確認してください。

テスト用に、GET リクエストを監視するサーバーを、Python を使用して素早くセットアップできます。コールバック URI は http://localhost:8888/callback に設定する必要があります。

$$ python -m http.server 8888

これで、次のテンプレートを使用して Frame.io アクセスをリクエストできます。[client_id][state] の値を入力します。state 用のランダム UUID をここで生成できます。

https://applications.frame.io/oauth2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fcallback&client_id=[client_id]&scope=offline+device.connect+asset.create&state=[state]&device_id=62f88d2a-1ae1-45e7-a6a0-81954e0cf2ff

承認フローを実行すると、404 エラーが返されます。これは、リクエストされているリソースを Python が認識せず、応答方法を知らないからです。ですが、心配は要りません。それでも承認リクエストは成功しました。サーバーによってターミナルに次のような出力が表示されることを確認します。

Serving HTTP on :: port 8888 (http://[::]:8888/) ...
::1 - - [08/Mar/2022 14:04:34] code 404, message File not found
::1 - - [08/Mar/2022 14:04:34] "GET /callback?code=[authentication_code]&scope=offline+device.connect+asset.create&state=[state] HTTP/1.1" 404 -

状態が送信したものと同じであることを確認する必要があります。authentication_code は、アクセストークンを取得するための次のステップで重要になります。

実際のアプリで、コールバックハンドラーは以下のようになります。

Python
1@handler("/frameio-callback")
2def do_get(request):
3 params = url.parse_query(request.url.parts.query)
4 if "error" in params:
5 raise AuthError(params["error"])
6
7 # Handles sending the authentication code and state to the proper user
8 MyApp.frameio_oauth_success(state=params["state"], code=params["code"])
9
10 # Render some sort of confirmation page for the user.
11 request.send_response(
12 code=200,
13 headers={"Content-type": "text/html"},
14 data=OauthSuccessPage()
15 )

手順 3:アクセストークンを取得する

これで authorization_code が取得されたので、アクセストークンを取得できます。この段階で、アクセストークンは既に付与されており、あとはそれをバックエンドにリクエストするだけです。

次のようにリクエストしましょう。

$curl -X POST https://applications.frame.io/oauth2/token \
> --form 'client_id=[client_id]' \
> --form 'state=[state]' \
> --form 'code=[authorization_code]' \
> --form 'redirect_uri=http://localhost:8888/callback' \
> --form 'grant_type=authorization_code' \
> --form 'scope=offline device.connect asset.create' \
> | python -m json.tool
OAuth エンドポイント

ほとんどのリクエストで使用されるホストは api.frame.io ですが、このリクエストのホストはそれとは異なり、applications.frame.io です。また、ここでは JSON データではなくフォームデータを使用しています。C2C OAuth エンドポイントは、フォームデータのみを受け入れます。

認証されると、他のエンドポイントは application/json ペイロードを受け入れますが、認証エンドポイントは application/x-www-form-urlencoded データではなく JSON を送信すると、エラーを返します。

各パラメーターについて説明します。

client_idFrame.io から発行された OAuth アプリ識別子。

state:ブラウザーへの元の承認リクエストに含めて、コールバックで受信した状態値。

code:コールバックで受信した承認コード。

redirect_uri:Frame.io のバックエンドに登録したのと同じリダイレクト URI。統合用に Frame.io に記録されているカンマ区切り URL リストにこの値がなかった場合、このリクエストは失敗します。

grant type:ソフトウェアデバイス承認フローでは、常に authorization_code です。

scope:コールバックで返された承認済みスコープと一致する必要があります。

次のようなレスポンスが返されます。

1{
2 "access_token": "[access_token]",
3 "expires_in": 3599,
4 "refresh_token": "[refresh_token]",
5 "scope": "offline device.connect asset.create",
6 "token_type": "bearer"
7}

デバイスが Frame.io で正常に承認されました。以降のリクエストで必要になるので、これらの値はいつでも参照できるようにしておいてください。ペイロードの内容を確認しましょう。

access_tokenFrame.io バックエンドの残り部分に対する鍵です。これらのチュートリアルで行う以降のリクエストのヘッダーにこれを追加する必要があります。

expires_inaccess_token の有効期限が切れるまでの秒数。このトークンの時間が経過したら更新が必要です。これについては、今後のチュートリアルで説明します。

refresh_tokenaccess_token の管理に使用できるトークン 。主に承認の更新に使用されますが、取り消しにも使用できます。

token_type:C2C API では常に bearer で、特に処理は不要です。

実際にプロジェクトに接続されるまでにはまだいくつかの手順があります。続けましょう。

手順 4:アカウントをリストする

次に、ユーザーが接続できるアカウントのリストを取得する必要があります。これはアクセストークンを必要とする最初の呼び出しであり、トークンはヘッダーに追加します。

$curl -X GET https://api.frame.io/v2/devices/accounts \
> --header "x-client-version: 2.0.0" \
> --header "Authorization: Bearer [access_token]" \
> | python -m json.tool
API エンドポイント仕様

/v2/devices/accounts のドキュメントは こちらに用意されています

認可ヘッダー

認可を必要とするすべてのエンドポイントについて、Authorization ヘッダーに access_token を追加する必要があります。値としてアクセストークンに Bearer (スペース込み)を事前に追加する必要があることに注意してください。

この呼び出しには、ユーザーが接続できるアカウントのリストが返されます。

1[
2 {
3 "_type": "account",
4 "display_name": "Hogwarts General",
5 "id": "46b7ea11-3041-4e2b-97f7-98fbf5c974c9"
6 },
7 {
8 "_type": "account",
9 "display_name": "Gryffindor",
10 "id": "e6007a3d-cad7-4666-9ee3-23c1af032060"
11 },
12 {
13 "_type": "account",
14 "display_name": "QUIDDITCH LEGENDS -- LETS GOOOOOOOOOO",
15 "id": "cc94119d-f957-4d6e-b8cf-0c095211b1b9"
16 }
17]

この段階で、このリストをユーザーに表示し、接続先アカウントを選択してもらいます。次に、次のステップでアカウントの id を使用して、ユーザーが C2C デバイスを接続できるプロジェクトをリストします。

手順 5:プロジェクトをリストする

次に、対象となるアカウントのプロジェクトのリストを取得する必要があります。

$curl -X GET https://api.frame.io/v2/devices/accounts/[account_id]/projects \
> --header "x-client-version: 2.0.0" \
> --header "Authorization: Bearer [access_token]" \
> | python -m json.tool
API エンドポイント仕様

/v2/devices/accounts/[account_id]/projects のドキュメントはこちらに用意されています

プロジェクトリストの対象となる account_id を URL に追加する必要があります。また、リソースパス全体が /devices/... で始まることにも注意してください。ここでは、ただプロジェクトをリストしているだけではなく、ユーザーに C2C **デバイス管理権限があるプロジェクトをリストしています。ユーザーが属しているプロジェクトがリストされない場合、該当プロジェクトの C2C デバイス管理権限がそのユーザーにはありません。

アカウントの場合と同様のレスポンスが返されます。

1[
2 {
3 "_type": "project",
4 "id": "921480ec-1225-424a-9447-19c61a3a1ef2",
5 "name": "Match Recordings"
6 },
7 {
8 "_type": "project",
9 "id": "ed5dbf4a-f146-416b-add0-74de98201876",
10 "name": "Year Book Material"
11 }
12]

アカウントの場合と同様、ユーザーにこのリストを表示し、接続するプロジェクトを選択できるようにする必要があります。また、アカウントの場合と同様、次のステップではプロジェクトの id が必要になります。

手順 6:プロジェクトに接続する

ユーザーが接続先プロジェクトを選択したので、準備が整いました。これが、ソフトウェアデバイスと Frame.io プロジェクトのペアリングを完了するための最後の手順です。

$curl -X POST https://api.frame.io/v2/devices/connect?project_id={project_id} \
> --header "x-client-version: 2.0.0" \
> --header "Authorization: Bearer [access_token]" \
> | python -m json.tool
API エンドポイント仕様

/v2/devices/connect のドキュメントはこちらに用意されています

プロジェクト ID は URL クエリパラメーターであり、承認ヘッダーを渡す必要があります。

次のようなレスポンスが返されます(簡潔にするため一部のデータは省略されています)。

1{
2 "_type": "project_device",
3 "asset_type": "video",
4 "authorization": {
5 "_type": "project_device_authorization",
6 "creator": {
7 "_type": "user",
8 "account_id": "93f872fb-9924-4e31-a430-2574e0742260",
9 "deleted_at": null,
10 "email": "hpotter@hoggyhoggyhogwarts.edu",
11 "id": "d473b5e1-08d2-4842-82ac-a6b01233dc2c",
12 ...
13 "name": "Harry Potter",
14 ...
15 },
16 "creator_id": "d473b5e1-08d2-4842-82ac-a6b01233dc2c",
17 "expires_at": null,
18 "id": "ee9f5949-b7fa-4c71-8480-6d4c60877c51",
19 "inserted_at": "2022-03-09T18:14:21.893283Z",
20 "project_device_id": "6a55d7f6-dfb7-46a1-bff8-a3acb2d3d1aa",
21 "scopes": {
22 ...
23 "asset_create": true,
24 ...
25 "id": "1e174fe9-5b53-48db-b556-c310c0848898",
26 "offline": true,
27 ...
28 }
29 },
30 "channels": [
31 {
32 "_type": "project_device_channel",
33 "asset_type": "video",
34 ...
35 }
36 ],
37 "creator_id": "d473b5e1-08d2-4842-82ac-a6b01233dc2c",
38 "deleted_at": null,
39 "device_id": "a8a4f3bf-196c-4748-832b-28f1d0801515",
40 "id": "93af90e7-ee89-4b47-86e6-c2750f3790b6",
41 ...
42 "name": "MyApp-62f88d2a-1ae1-45e7-a6a0-81954e0cf2ff",
43 "project": {
44 "_type": "project",
45 "id": "921480ec-1225-424a-9447-19c61a3a1ef2",
46 "name": "Testbed"
47 },
48 "project_id": "921480ec-1225-424a-9447-19c61a3a1ef2",
49 "status": "online",
50 ...
51}
プロジェクトは一度に 1 個

デバイスと一度にペアリングできるプロジェクトは 1 個だけであり、別のプロジェクトに対して別のペアリング操作を実行すると、それまで接続されていたプロジェクトとの接続が削除されます。

あのようなレスポンスペイロードが返ってきたら、成功です。見事、やり遂げました。最初の Camera to Cloud デバイスを承認しました。ご苦労さまでした。

最後に、プロジェクト名をユーザーに表示して、接続先プロジェクトを確認できるようにしてください。

サードパーティの OAuth ライブラリの使用

Frame.io では標準の Oauth 2.0 フローを使用しています。セキュリティ強化のため、PKCE を適用します。統合のこの部分を処理するためのライブラリは多数あります。

ここでは、一般的な OAuth ライブラリをいくつか示します。

プログラミング言語名前URL
SwiftOAuthSwiftGitHub
Pythonrequests-oauthlibGitHub
Flutteroauth2_clientGitHub

Frame.io は、特定のデバイスを識別するための device_id フィールドを追加します。これは追加のカスタムフィールドです。どのライブラリを使用することにしても、カスタムフィールドはおそらくサポートされていますが、忘れずに追加してください。

トラブルシューティング

ここをご覧になっているということは、何かがおかしいのですね。サードパーティとの統合は、エラーなしとはいかないものです。このセクションでは、一般的な問題の一覧と、それらを解決できる可能性が最も高い手順について説明します。次の一覧を参照して、目下の問題と一致するものがないか確認してください。エラーガイドも、API エラーを調べるための優れたリソースです。

ここで解決策が見つからない場合は、発生した問題をお聞かせください。ここに追加します。

**接続先のアカウントまたはプロジェクトが返されなかった:**アカウントやプロジェクトをリストしていて、接続先のアカウントまたはプロジェクトがリストされない場合は、いくつかの問題が発生している可能性があります。Frame.io で、接続先プロジェクトに移動し、「C2C Connections」タブをクリックします。これは、何がうまくいっていないのかを判断するのに役立ちます。

  • **アカウントで C2C が有効になっていない:**画面が空白で、アカウントで C2C が利用できないというメッセージが表示された場合、アカウント管理者がアカウント設定で該当プロジェクトの C2C を有効にする必要があります。
  • **デバイス管理者ではない:**画面が空白で、権限がないというメッセージが表示された場合、アカウント管理者が、C2C デバイスへの接続を許可されているユーザーの権限を変更するか、それらの権限を持つロールにユーザーを追加する必要があります。

**無効なクライアントエラー:**デバイスに関してお客様から提供された情報が、当社が記録しているものと一致しない場合、invalid_client が返されます。多くの場合、これは client_secretclient_id または redirect_uri が Frame.io のバックエンドにあるファイルの情報と一致しないことを意味します。

**不正なリクエストエラー:**リクエストデータの形式が何らかの形で不正な場合、bad_request が返されます。フィールド名のスペルが間違っていたり、必須フィールドの追加を忘れたりしていないことを再確認してください。

次のステップ

まだの場合は、当社チームにお問い合わせください。そのうえで、次のガイドに進んでください。ご連絡をお待ちしております。