見出し画像

GPTsのActionsの認証とGoogle APIについての話。

最近GPTsをずーといじっていて、しょっちゅうGPT4のメッセージ数の上限に引っかかってます。はい。
もっと多くていいと思いますよ。上限。

今回作ろうとしているGPTsで動画の概要欄の情報が欲しかったのですが、ChatGPTのブラウジング機能ではYoutubeにアクセスできないので、Youtube Data API使用して取得しようとして、認証にドはまりしたのでGPTsの認証周りの情報について書いていこうと思います。

この記事ではAPIキーをクエリに設定するしかない場合でも、漏洩しないようにする方法について記載しています。


Google API

今回自分が試行錯誤したのはYoutube Data APIですが、認証の方法はGoogle APIで共通だと思います。

Google Cloudが提供しているAPIで使用できる認証方法は以下の2つです。

  • APIキーをクエリ(keyパラメータ)に指定する方法

  • OAuth2.0を使用する方法

まずはAPIキーがお手軽なので、APIキーを発行しましょう。

Google Cloud ConsoleでAPIキーを作成します。
Google APIを使用するにはプロジェクトを作成して、APIを有効化し、APIキーを発行する必要があります。
今回そこは本題ではないので割愛します。
以下のようなサイトなどを参考にしてください。
https://www.zenrin-datacom.net/solution/gmapsapi/api_key

まずはこれについて試したことを記載します。

GPTsのActionsのAPIキーについて

GPTsのActionsの認証には以下のように3パターンあり、API Keyについても3パターンあります。

Authentication

ここがGPTsのクセというか厄介なところで結構ハマってるのではと思いますが、ここで設定できるAPI KeyはどのAuth Typeを選んでも、リクエストのHeaderに設定される値でありクエリーには設定されないということです。

ではどうするかというと、OpenAPI SchemaにAPI Keyのクエリパラメータ(keyパラメータ)を書いてください。
そしたら以下の2つの方法があります。

  • Instructionsに以下のように指示する
    「APIキー(keyパラメータ)は次を使用してください。:{YOUR_API_KEY}」

  • OpenAPI Schemaのクエリパラメータのschemaにenumで記載する

- name: key
  in: query
  required: true
  schema:
    type: string
    enum:
      - "AIzaSyCUnxtcErx8T8r6oFiyqceCFtQWrn0oxkg"

これでリクエストパラメータにAPI Keyを設定することができると思います。

ですがこれだとGPTsがAPIをコールしたときのログで、API Keyが以下のように公開されてしまいます。

すでに削除したkeyです。

作ったGPTsを公開する予定がなく自身で使うだけであればこれで問題ありません。

GPTsを公開しようとしている場合、APIキーが公開されてしまいます。APIキーを公開してしまうとどんな問題があるかGPTさんに聞いてみました。

まずいですねー

OAuth2.0について

GPTsのActionsのクエリーにAPI Keyを設定するのはどう頑張っても漏洩してしまいそうです。Google APIにはもう一つOAuthでの認証があるのでこちらも見てみましょう。

認証情報を作成し、OAuth クライアント IDをWebアプリケーションで作成、クライアントシークレットなどのOAuthの各項目を設定していきます。

その他の項目は以下を設定します。

今回試していたのはYoutube Data APIで動画の概要欄(description)の取得ですが、これにはScopeとしyoutube.readonlyの権限が必要となり、これは「機密性の高いスコープ」となっていて公開するには検証が必要となってしまいます。
もし使用するAPIの必要なスコープが「非機密のスコープ」であれば検証は不要なのでこれで公開することができるのではないでしょうか?

テストではOAuthで動作させることができたので、公開させようとしたところ、「機密性の高いスコープ」に該当する場合検証が必要となり、GoogleのOAuth申請が必要となってしまいます。

OAuth申請のためには以下が必要となります。

  • アプリのプライバシー ポリシーへの公式リンク

  • スコープから取得した Google ユーザーのデータをどのように使用する予定であるかを示す YouTube 動画

  • 機密データや制限付きのユーザーデータへのアクセス権が必要である理由を Google に通知する、書面による説明

上記を全て用意できる人はいいですが、GPTsのためにアプリのサイトを作ったり説明のためのYouTube 動画を作成するのは少し難しいのではないでしょうか?

APIプロキシの作成

クエリに乗せるのがダメで、OAuthも使えないとなったので他の方法を模索します。APIプロキシを作成しGPTsとAPIとの間に入ってもらい、API Keyを隠蔽するようにします。[GPTs] ⇒ [APIプロキシ] ⇒ [API]の流れです。
APIプロキシ内の環境変数などにAPI Keyを設定することにより漏洩しないようにします。

プロキシの作成を無料で作成するにはいくつかサービスがあると思いますが、今回はCloudFlare Workersを利用しました。

CloudFlare Workers無料枠

100,000 per day
10 milliseconds of CPU time per invocation

https://developers.cloudflare.com/workers/platform/pricing/

CloudFlare Workersは無料で1日10万リクエスト、10ミリ秒以内のCPU時間までなら可能なようです。プロキシにぴったりです。

Workersの作成

CloudFlare Workersに登録して、早速作ります。

ワーカの作成を押して、名前を決めます。なんでもいいです。

早速デプロイして、コードの編集をしましょう。CloudFlare Workersは全てWebで完結させられるので環境を作る必要はないです。

プロキシの認証

以下のようにまずAPIプロキシにトークン認証を作成します。
APIプロキシに自由にアクセスできると、プロキシから呼ぶ外部のAPI(Youtube Data APIなど)もコールされてしまい、問題があるのでトークンによって制限します。トークン認証といってもGPTsとプロキシで同じものであればいいのでランダムな文字列であればなんでもいいです。

export default {
  async fetch(request, env, ctx) {
    // トークン認証
    if (request.headers.get('x-api-token') !== env.TOKEN) {
      // 401 Unauthorizedレスポンスを返す
      return new Response('Invalid authentication token.', { status: 401 });
    }
    return new Response('Hello World!');
  },
};

認証の方法はリクエストのheaderに「x-api-token」という物を設定し、CloudFlare Workersの環境変数に設定したTOKENと比較するというものです。headerのパラメータ名も環境変数名も好きなものを使用してください。ここでは「x-api-token」と「TOKEN」にしました。

CloudFlare Workersの環境変数は以下の「設定」で設定できます。

設定の変数に環境変数があるのでここに設定します。

Youtube Data APIに設定するAPI KEYもここに設定しておきます。値は暗号化できるので暗号化します。

GPTs側は以下のように「Authentication Type」をAPI Keyにして、「Custom」にして、上で決めた項目名にします。


APIコール

後はコールするAPIのパラメータを組み立てリクエストを送信してレスポンスを返却するだけです。以下にWorkersの全体を載せます。

export default {
  async fetch(request, env, ctx) {
    if (request.headers.get('x-api-token') !== env.TOKEN) {
      // 401 Unauthorizedレスポンスを返す
      return new Response('Invalid authentication token.', { status: 401 });
    }
    
    const url = new URL(request.url)
    const apiURL = 'https://www.googleapis.com/youtube/v3/videos'
    
    // APIキーと追加のクエリパラメータを設定
    const params = new URLSearchParams(url.search)
    params.set('part', 'snippet')
    params.set('fields', 'items(snippet(description))')
    params.set('key', env.API_KEY)

    // リファラーの設定
    const modifiedHeaders = new Headers(request.headers);
    modifiedHeaders.set('Referer', '{自身のWorkersのURL}');

    // YouTube Data APIにリクエストを転送
    const apiReq = new Request(apiURL + '?' + params, {
      method: request.method,
      headers: modifiedHeaders
    })

    // YouTube APIからのレスポンスを返す
    return fetch(apiReq)
  },
};

Google APIはAPI Keyに制限をつけることができます。自分は念のため「ウェブサイトの制限」でWorkersのURLのみを許可するようにしています。
リファラは自動で設定されないのでコード上で自身のWorkersのURLを指定しています。

後はGPTsのActions側のOpen API SchemaをAPIプロキシに修正すれば完成です。

まとめ

GPTsでYoutube動画の概要欄が取得したかっただけなのですが、随分苦労しました。YoutubeがGPTのアクセスをブロックしてなければこんなことにはならなかったのですが。
API Keyをクエリに乗せる方法も、もしかしたらプロンプトを工夫すればGPTに出力させない方法があるかもしれないです。どなたかご存知であれば教えて下さい。

今作ってるGPTsもどうにも安定しないので調整中です。公開できるほどに安定させられたら、その方法もまたnoteにかけたらと思ってます。

以上です。ご覧いただきありがとうございました。

いいなと思ったら応援しよう!