3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Google API認証の3方式を実装して仕組みまで理解する - APIキー/OAuth/サービスアカウント

Last updated at Posted at 2025-12-21

リンクアンドモチベーションでSREをしている井川です。
GoogleのAPIを使おうと思った際に、下記の通り認証方法を作成する方法が3種類あったのでそれぞれ試しつつ、仕組みについて整理しました。
image.png

試したこと

Goal:コードを実行して、スプレッドシートの最初のセルを出力させる。

APIキー

設定

  • APIキーを作成する
    Pasted image 20251214170243.png
  • 取得したAPIキーを.envのAPI_KEYに反映する

実行

  • コード実行
import os
from dotenv import load_dotenv
from googleapiclient.discovery import build

# Load environment variables from .env file
load_dotenv()

API_KEY = os.getenv('API_KEY')
SPREADSHEET_ID = os.getenv('SPREADSHEET_ID')

service = build('sheets', 'v4', developerKey=API_KEY)
result = service.spreadsheets().values().get(
    spreadsheetId=SPREADSHEET_ID,
    range='A1'
).execute()

print(result.get('values', [['']])[0][0])
  • 成功

OAuthクライアントID

設定

  • OAuthクライアントIDを作成する
    Pasted image 20251214173848.png
  • 取得した情報をcredentials.jsonに保存する
  • 承認済みのリダイレクトURIを設定する
    Pasted image 20251214175228.png
  • テストユーザーを追加する
    image.png

実行

  • コード実行
import os
from dotenv import load_dotenv
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build

load_dotenv()

SPREADSHEET_ID = os.getenv('SPREADSHEET_ID')
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
creds = flow.run_local_server(port=8080)

service = build('sheets', 'v4', credentials=creds)
result = service.spreadsheets().values().get(
    spreadsheetId=SPREADSHEET_ID,
    range='A1'
).execute()

print(result.get('values', [['']])[0][0])
  • アカウントのログインを求められる
  • テストユーザーで設定しているユーザーでログインする
  • 成功画面が出てコード実行が成功する
    image.png

サービスアカウント

設定

  • サービスアカウントを作成する
  • キーを追加する
  • スプレッドシートの共有対象にサービスアカウントを追加する
  • 作成されたJSONファイルをservice-account.jsonに保存する

実行

  • コード実行
import os
from dotenv import load_dotenv
from google.oauth2 import service_account
from googleapiclient.discovery import build

load_dotenv()

SPREADSHEET_ID = os.getenv('SPREADSHEET_ID')
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

creds = service_account.Credentials.from_service_account_file('service-account.json', scopes=SCOPES)
service = build('sheets', 'v4', credentials=creds)
result = service.spreadsheets().values().get(spreadsheetId=SPREADSHEET_ID, range='A1').execute()

print(result.get('values', [['']])[0][0])
  • 成功

認証方法の仕組み

APIキー

シンプルな仕組みですね。
その分、非公開データにアクセスできない特徴があります。
image.png

OAuthクライアントID

ユーザーのアクションが必要になるのが特徴ですね。
image.png
https://developers.google.com/identity/protocols/oauth2?hl=ja

サービスアカウント

ユーザー不在でも動作するのが特徴ですね。
image.png
https://developers.google.com/shopping-content/guides/how-tos/service-accounts?hl=ja

シーケンス図作成の過程で出てきた不明点の解消

  • client_secretはどこで発行される?
    • OAuthクライアントIDを作成した際に発行され、credentials.jsonとしてダウンロードする
    • この情報があることでサーバーが正規のものであることを証明できる
  • Bearerの仕組みとは?
    • 認証方式の1種であり、トークン所持者に権限を付与する
    • 平文で送られるため、必ず暗号化されるHTTPSで送る
  • トークン検証の方法とは?
    • JWTと不透明トークンの2種類があり、それぞれでトークンが認可情報を処理および検証する方法が異なる
  • JWTとは?
    • JSON Web Token
    • 認証に必要な情報をすべてもつ自己完結型のトークン
    • サービス間で認証・認可のデータを伝送する際に使われるJSONオブジェクトと署名を表現するアプローチ
      • ex. RSA(秘密鍵で署名して認証サーバーに送り、認証サーバーでは公開鍵で署名の検証をする)
    • https://auth-wiki.logto.io/ja/jwt
  • 不透明トークンとは?
    • クライアントにとって意味のないランダムでユニークな文字列
    • サーバーのデータベースで認可データを検索するための参照キーとして使われる
    • https://auth-wiki.logto.io/ja/opaque-token

まとめ

それぞれの認証の裏に、様々な技術や仕組みがあることを学びました。
今後使う上では、下記のように適切に使い分けていきたいと思います。

  • APIキー
    • 公開データにのみアクセスする場合(非公開データにはアクセスできない)
  • OAuthクライアントID
    • ユーザーごとで異なるデータにアクセスする場合
  • サービスアカウント
    • ユーザー不在で通信する場合
    • バックエンドの自動処理の場合
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?