エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

API Key 無しで Gemini をセキュアに Google Apps Script から利用する

本文に関係ないドッグランに行ったときの犬たち

こんにちは、AI・機械学習チームの山本(@hiro_o918)です。 このブログは AI・機械学習チームブログリレー 5 日目の記事です。

これまでのリレー記事でも出てきたように、弊社でも AI を活用したプロダクト開発が進んでいます。 それに加えてビジネスサイドでも AI 活用が進んでおり、OSS 版 Dify を導入・運用したり、Google Workspace に付帯する Gemini を活用したりしています。

このような状況から、AI 機能の実装に関してビジネスサイドから相談を受ける機会が多いのですが、その際には利便性だけでなくセキュリティ面も充分考慮した上で導入する必要があります。 そこで、今回は Google Apps Script (GAS) を使って、Google の生成 AI モデルである Gemini を API キー無しでセキュアに利用する方法を解説します。

比較対象: API キーを使った方法

API キーを使って Gemini API を呼び出す場合、次の記事にあるように Google AI Studio で API キーを取得し、GAS から HTTP リクエストを送信する方法があります。

ai.google.dev

この方法は簡単に始められますが、API キーを発行し管理する必要があるという点においてセキュリティ上のリスクがあります*1。 特に GAS のように分散して利用される環境において、どこでも利用可能な API キーを使用することは好ましくありません。

API キー無しで Gemini を利用する方法

そこで、今回は Google Cloud の Vertex AI API を利用し、Google Workspace の OAuth 認証を通じてセキュアに Gemini を利用する方法を紹介します。

Google Cloud の設定

まず、Gemini API を利用するための Google Cloud の設定をします。 下記は Terraform を使った設定例です。

locals {
  project = "your-project-id"
}

resource "google_project_service" "vertex_ai" {
  project            = local.project
  service            = "aiplatform.googleapis.com"
  disable_on_destroy = true
}

resource "google_project_iam_member" "staff_is_vertex_ai_user" {
  for_each = toset([
    # AI API 利用に必要な権限
    "roles/aiplatform.user",
    # GAS と Google Cloud Platform を連携する際に必要
    "roles/editor",
  ])

  project = local.project
  role    = each.value
  # 組織内のユーザーグループを指定
  member  = "group:ai-user@example.com"
}

この設定は次のことを行います:

  1. Vertex AI API が有効化
  2. 指定したグループに Vertex AI API を利用するための権限を付与

Google Cloud と Google Workspace の連携は非常に強力で、社内のユーザーやグループに対して簡単に権限を付与できます。 個人的に非常に便利な機能だなと感じる場面が多いです。 注意点として、GAS と Google Cloud を連携するためには roles/editor 権限が必要な点です。 そのため、本番環境のプロジェクトとは別に開発用のプロジェクトを 1 つ作成することをお勧めします。 プロジェクトを分けることでコスト管理もしやすくなるメリットもあります。

ここまでが開発者側で行う事前準備になります。

Google Apps Script (GAS) の設定

次に、GAS を設定して、Gemini API を呼び出すための準備をします。

GAS プロジェクトの作成

任意の Google Workspace アプリケーション(ドキュメント、スプレッドシート、フォームなど)から GAS を開きます。

メニューから「拡張機能」>「Apps Script」を選択

マニフェストファイルの設定

GAS プロジェクトが外部 API と通信するための適切な権限を設定します。

マニフェストファイルの表示

  1. Apps Script エディタの「プロジェクトの設定」(⚙️)をクリックします
  2. 「マニフェスト ファイルをエディタで表示する」をオンにします
  3. マニフェストファイルを開き、次のように設定します:
{
  "timeZone": "Asia/Tokyo",
  "dependencies": {},
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/cloud-platform"
  ],
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

Google Cloud との連携

GAS から Vertex AI API を呼び出すには、GCP プロジェクトと紐付ける必要があります。

Google Cloud プロジェクト設定

  1. プロジェクト設定から「Google Cloud Platform(GCP)プロジェクト」セクションへ移動
  2. GCP プロジェクト番号を入力(既存のプロジェクトまたは新規作成したプロジェクト)

Gemini API 呼び出しの実装

コア機能: Gemini API 呼び出し関数

以下は、Vertex AI の Gemini API を呼び出すための関数です:

/**
 * Vertex AI の Gemini API を呼び出す
 *
 * @param {string} prompt Gemini モデルに送信するテキストプロンプト
 * @return {string} Gemini モデルからの応答テキスト
 */
function callGeminiApi(prompt) {
  // GCP プロジェクト ID を設定
  const projectId = "your-project-id";
  const region = "us-central1";
  const modelId = "gemini-2.5-flash";

  // OAuth トークンの取得(GAS が自動的に処理)
  const accessToken = ScriptApp.getOAuthToken();

  // API エンドポイント
  const endpoint = `https://${region}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${region}/publishers/google/models/${modelId}:generateContent`;

  // リクエストペイロードの構築
  const payload = {
    contents: [
      {
        role: "user",
        parts: [
          {
            text: prompt,
          },
        ],
      },
    ],
    // 必要に応じて生成設定を追加
    generationConfig: {
      maxOutputTokens: 2048,
      temperature: 0.4,
      topP: 1,
    },
  };

  // HTTP リクエストオプションの設定
  const options = {
    method: "post",
    contentType: "application/json",
    headers: {
      Authorization: "Bearer " + accessToken,
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  };

  // API リクエストの実行
  // Ref: レスポンスの構造の詳細は公式ドキュメントを参照
  // https://ai.google.dev/api/generate-content?hl=ja#generatecontentresponse
  const response = UrlFetchApp.fetch(endpoint, options);
  const responseCode = response.getResponseCode();
  const responseBody = response.getContentText();

  // レスポンス処理
  if (responseCode === 200) {
    const jsonResponse = JSON.parse(responseBody);

    // 標準的なレスポンス構造の処理
    if (
      jsonResponse.candidates &&
      jsonResponse.candidates.length > 0 &&
      jsonResponse.candidates[0].content &&
      jsonResponse.candidates[0].content.parts &&
      jsonResponse.candidates[0].content.parts.length > 0 &&
      jsonResponse.candidates[0].content.parts[0].text
    ) {
      return jsonResponse.candidates[0].content.parts[0].text;
    } else {
      Logger.log("Unexpected response structure: " + responseBody);
      return "Error: Could not parse the response from Gemini API. Check logs for details.";
    }
  } else {
    Logger.log(
      "Error calling Gemini API: " + responseCode + " - " + responseBody
    );
    return (
      "Error: Failed to call Gemini API. Status: " +
      responseCode +
      ". Response: " +
      responseBody
    );
  }
}

テスト関数

/**
 * Gemini API 呼び出しをテストする関数
 */
function testGeminiCall() {
  const prompt = "Google Apps Script の主な特徴と利点を5つ挙げてください。";
  const result = callGeminiApi(prompt);

  // 結果をログに出力
  Logger.log(result);

  // UI で結果を表示(スプレッドシートから実行する場合)
  // SpreadsheetApp.getUi().alert('Gemini API レスポンス', result, SpreadsheetApp.getUi().ButtonSet.OK);
}

まとめ

今回は API キー無しで Google Apps Script から Gemini API をセキュアに利用する方法を紹介しました。 この方法では、Google Cloud の OAuth 認証を利用して、API キーをコード内にハードコーディングすることなく、セキュアに Gemini を利用できます。 また、このコードやプロジェクトに認証情報の紐づけが不要なため、コードとしての再利用性も高まります。 今後も利便性とガバナンスを両立させた AI 活用の方法を模索していきたいと思います。

We are hiring!

エムスリー AI・機械学習チームでは、プロダクト開発にとどまらず全社を上げた AI 活用の取り組みも進めています。 垣根なく AI を活用した価値の提供に興味がある方は、ぜひ一緒に働きましょう!

エンジニア採用ページはこちら

jobs.m3.com

カジュアル面談もお気軽にどうぞ

jobs.m3.com

インターンも常時募集しています

open.talentio.com

*1:2025/06/30 訂正: ハードコーディングするという記述をしておりましたが、プロパティストアを使うことでハードコーディングは回避できるため削除しました