---
date: 2024-03-27 11:00:00
description: Gmailのセキュリティ仕様変更に伴い、FileMakerからのメール送信でエラーが発生する事例が増えています。代替策としてGASを利用する場合の懸念点である「リフレッシュトークン有効期限（7日後に切れる問題）」について、実際のOAuth URLを解析して検証しました。
title: Google Apps ScriptのOAuth認証URLとリフレッシュトークン有効期限を調査
updatedDate: 2025-12-17 09:00:00
---

###
    更新：
    2025-04-08



その後、リフレッシュトークンについての調査結果を、以下の記事にまとめています。


[Google Apps Script内部のリフレッシュトークンは、1週間後も有効か？（7日認証切れ問題） | 株式会社フルーデンス](/blog/2024/04/08/google-apps-script-refresh-token-access-token-after-one-week/)

## きっかけ

Gmail関連のアップデートの影響か、最近FileMakerからGmailのSMTPサーバーを使ってメール送信していた環境で、「送信エラーになる」という話題をTwitterなどでよく見かけるようになりました。

対策として、**Google Apps Script (GAS) を経由してメールを送信する方法**が考えられますが、そこで気になるのが**「認証トークンの有効期限」**です。もし頻繁に再認証（再同意）が必要になるようでは、自動化の運用に乗せるのが難しくなります。

そこで、GASがバックグラウンドでどのようなOAuth認証URLを発行し、アクセストークンを取得しているのか詳しく調べてみました。

## GASの認証URLを確認する

実際にGASのエディタでスクリプトを実行し、初回認証が必要になった際に生成されるURLを取得して解析してみます。


```js
function myFunction() {
  // 認証ダイアログを出すために、明示的にトークンを取得するメソッドを実行
  const token = ScriptApp.getOAuthToken();
  console.log(token);
}
```

  認証フローをトリガーするためのテストコード

スクリプト実行時に表示される認証用URLを確認した結果がこちらです。

![GASエディタの実行ログに表示された承認URLとプロンプト](gas-execution-log.png)

*GASのエディタと承認を要求されている画面*

![Googleアカウントへのアクセスリクエスト画面](gas-oauth-consent-screen.png)

*OAuth認証のリクエスト許可画面*

## 取得したURL


```js
const url = new URL(`https://accounts.google.com/o/oauth2/auth/oauthchooseaccount?client_id=123456789123-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fscript.google.com%2Foauthcallback&state=13464014877097984000&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send&response_type=none%20gsession&access_type=offline&approval_prompt=force&hl=ja&login_hint=sample%40gmail.com&service=lso&o2v=1&theme=mn&ddm=0&flowName=GeneralOAuthFlow`);
console.log(url);
```

  ログから取得したOAuth認証用URL

## URLをパースした結果

取得したURLをNode.jsなどでパース（解析）してみると、以下の構造になっていることがわかります。


```js
URL {
  href: 'https://accounts.google.com/o/oauth2/auth/oauthchooseaccount?client_id=123456789123-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fscript.google.com%2Foauthcallback&state=13464014877097984000&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send&response_type=none%20gsession&access_type=offline&approval_prompt=force&hl=ja&login_hint=sample%40gmail.com&service=lso&o2v=1&theme=mn&ddm=0&flowName=GeneralOAuthFlow',
  origin: 'https://accounts.google.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'accounts.google.com',
  hostname: 'accounts.google.com',
  port: '',
  pathname: '/o/oauth2/auth/oauthchooseaccount',
  search: '?client_id=123456789123-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fscript.google.com%2Foauthcallback&state=13464014877097984000&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send&response_type=none%20gsession&access_type=offline&approval_prompt=force&hl=ja&login_hint=sample%40gmail.com&service=lso&o2v=1&theme=mn&ddm=0&flowName=GeneralOAuthFlow',
  searchParams: URLSearchParams {
    'client_id' => '123456789123-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
    'redirect_uri' => 'https://script.google.com/oauthcallback',
    'state' => '13464014877097984000',
    'scope' => 'https://www.googleapis.com/auth/gmail.send',
    'response_type' => 'none gsession',
    'access_type' => 'offline',
    'approval_prompt' => 'force',
    'hl' => 'ja',
    'login_hint' => 'sample@gmail.com',
    'service' => 'lso',
    'o2v' => '1',
    'theme' => 'mn',
    'ddm' => '0',
    'flowName' => 'GeneralOAuthFlow' },
  hash: ''
}
```

  URLパラメータの解析結果

パラメータを見ると、`access_type` に `offline` が設定されていることがわかります。

これは、**「リフレッシュトークン（更新トークン）」を発行する**という指定です。Google内部でこのリフレッシュトークンが管理されており、アクセストークンの期限が切れても、自動的に更新してくれる仕組みになっていると思われます。

## リフレッシュトークンの有効期限について

ここで少し懸念点があります。通常、Google Cloud Platform (GCP) で外部アプリとして同意画面を設定し、ステータスが「テスト中」の場合、**リフレッシュトークンが7日後に期限切れ**になるという仕様があるからです。


> 外部ユーザータイプ用に OAuth 同意画面が構成され、公開ステータスが「テスト中」である Google Cloud Platform プロジェクトには、7 日後に期限切れになる更新トークンが発行されます。
>
>       ただし、リクエストされた OAuth スコープが、名前、メールアドレス、ユーザー プロファイル（ userinfo.email, userinfo.profile, openid スコープ、または OpenID Connect の同等のもの）のサブセットである場合を除きます。


    [OAuth 2.0 を使用して Google API にアクセスする | Authorization | Google for Developers](https://developers.google.com/identity/protocols/oauth2?hl=ja#expiration)


![GCPドキュメントの更新トークン有効期限に関する記述](gcp-refresh-token-expiration-docs.png)

*Google Cloud Platform ドキュメント：更新トークンの有効期限について*

しかし、今回のGASは、個別のGCPプロジェクトを紐付けず、GAS標準の「デフォルトのCloudプロジェクト」を使用しています。

この場合、テストモード扱いにはならず、**7日後になっても期限が切れない**というのが一般的な理解です。もしこれが切れてしまうと、世界中のGASのトリガー実行が毎週止まってしまうことになるためです。

おそらく期限切れは発生しないと考えていますが、確実な検証のため、7日後に再度スクリプトを実行して確認してみたいと思います。