Kon's DX Lab - Case Study

Day 61|PythonでLogiless APIにアクセス!OAuth2認証スクリプトを構築

Published on 2025-06-01

🔬 Case Study Summary
Problem

(ここに課題を記述)

Result

(ここに具体的な成果を記述)


Tech & Process

(ここに採用技術とプロセスを記述) コードを詳しく見る »

こんにちは、こんです🦊

今日は、PythonでLogiless APIと安全に連携するためのOAuth2認証スクリプトを整えました!

GASでも実装しましたが、今回はより柔軟で自動化しやすいPython版の準備です。定期実行やCLIベースのスクリプトとの相性も抜群です。


実験のきっかけ:「PythonからLogilessを扱いたい」

こんな悩み、ありませんか?

  • GASでは表現しにくい柔軟なロジックをPythonで書きたい

  • バッチ処理・非同期実行・Slack通知などを組み込みたい

  • OAuth2認証が面倒そうで手を出せていない…

そこで、認証まわりをテンプレ化して、すぐAPI利用に入れるスクリプトを作りました。


作ってみたもの(logiless_auth.py)

構成のポイントは次のとおりです:

  • ✅ .env で機密情報(CLIENT_ID / CLIENT_SECRET)を管理

  • ✅ 認証URLの生成&手動コード取得

  • ✅ 初回トークン保存(access_token / resh_token)

  • ✅ 有効期限管理&自動リフレッシュ

  • ✅ get_authorized_headers() でいつでもAPIを呼び出せる


logiless_auth.py

import os
import json
import time
import requests
import webbrowser
from dotenv import load_dotenv

load_dotenv()

TOKEN_FILE = 'config/logiless_token.json'
os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True)

CLIENT_ID = os.getenv('LOGILESS_CLIENT_ID')
CLIENT_SECRET = os.getenv('LOGILESS_CLIENT_SECRET')
REFRESH_URL = 'https://app2.logiless.com/oauth2/token'

def prompt_user_for_auth():
    url = generate_authorization_url()
    print(f"🔑 以下のURLをブラウザで開いて認証コードを取得してください:\n{url}\n")
    try:
        webbrowser.open(url)
        print("🌐 ブラウザを自動で開きました。")
    except Exception as e:
        print(f"⚠️ ブラウザを開けませんでした: {e}")

def generate_authorization_url():
    base_url = "https://app2.logiless.com/oauth/v2/auth"
    redirect_uri = "https://example.com/callback"
    return (
        f"{base_url}?response_type=code&client_id={CLIENT_ID}&redirect_uri={redirect_uri}"
    )

def fetch_initial_token(auth_code):
    redirect_uri = "https://example.com/callback"
    response = requests.post(REFRESH_URL, data={
        "grant_type": "authorization_code",
        "code": auth_code,
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "redirect_uri": redirect_uri
    })
    if response.status_code != 200:
        raise Exception(f"❌ 初回認証トークン取得失敗: {response.text}")
    token_data = response.json()
    token_data["acquired_at"] = int(time.time())
    save_token(token_data)
    print("✅ 初回トークン取得成功")
    return token_data

def load_token():
    with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
        return json.load(f)

def save_token(token_data):
    with open(TOKEN_FILE, 'w', encoding='utf-8') as f:
        json.dump(token_data, f, ensure_ascii=False, indent=2)

def is_token_expired(token_data):
    expires_in = token_data.get('expires_in')
    acquired_at = token_data.get('acquired_at', 0)
    return time.time() > (acquired_at + expires_in - 60)  # 1分前に更新

def refresh_token_if_needed():
    token_data = load_token()
    if not is_token_expired(token_data):
        return token_data['access_token']

    refresh_token = token_data.get('refresh_token')
    if not refresh_token:
        raise Exception("❌ refresh_token がありません。初回認証が必要です。")

    response = requests.post(REFRESH_URL, data={
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'grant_type': 'refresh_token',
        'refresh_token': refresh_token
    })

    if response.status_code != 200:
        raise Exception(f"❌ トークン更新失敗: {response.text}")

    new_token = response.json()
    new_token['acquired_at'] = int(time.time())
    save_token(new_token)
    print("🔄 アクセストークンを更新しました。")
    return new_token['access_token']

def get_authorized_headers():
    token = refresh_token_if_needed()
    return {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }

if __name__ == "__main__":
    prompt_user_for_auth()
    auth_code = input("🔐 認可コードを貼り付けてください: ")
    fetch_initial_token(auth_code)
    print("🔑 認証が完了しました。トークンを保存しました。")

🔍 現時点でのネック:認可コードは手動で貼り付けが必要

実はこのPython版、最初の認証時にだけ"人の手"が必要になります。

1. 認証URLをブラウザで開く
2. Logilessにログイン&許可する
3. 表示された認可コードをコピー
4. ターミナルに貼り付ける
auth_code = input("🔐 認可コードを貼り付けてください: ")
fetch_initial_token(auth_code)

これは「ローカルアプリケーションからOAuthを使う」際の一般的な制約です。
GASのように redirect_uri をGoogle側で完結できないため、リダイレクト先を https://example.com/callback などにして「人間がコピーして戻る」という手段を取らざるを得ません。

🧩 今後の改善候補

  • Flask や FastAPI を使って簡易Webサーバを立て、localhostで自動受け取りできるようにする

  • ElectronやTkinterなどでGUIラッパーを作って、手順を簡略化する

  • 一度認証したトークンを複数端末で共有する設計(例:S3やGCSで管理)


まとめ:GASに加えてPythonからもAPI活用が可能に

これでLogiless APIとの安全な接続環境が整いました。

GASと違い、Pythonなら:

  • 他サービスとのAPI連携

  • 自動実行の柔軟な制御

  • データ処理や統計分析との統合

などの可能性が広がります。
「認証がネックで手を出せなかった」人にも、ぜひ試してもらいたい仕組みです。

それでは、また次の実験で!🦊


#Python #API連携 #Logiless #業務効率化 #100日チャレンジ #ChatGPTで自動化