Communitygithub.com

vellum-ai/vellum-assistant

OAuth2を介してOura Ringに接続—アプリ登録、トークン交換、認証情報の保存

vellum-assistant とは?

このスキルは、Oura Ring(Gen3またはRing4)から睡眠、心拍数、準備度、活動、その他の健康データをOura Cloud API V2経由で取得するための統合を提供します。ユーザーは開発者アプリケーションを登録し、OAuth2フローを実行してアクセストークンを取得し、それを安全に保存します。保存されたトークンは、curlコマンドを使ってAPIエンドポイントに直接アクセスするために使用でき、データの取得や接続の確認が可能です。このスキルは、Claude Codeや同様のAIエージェント環境での使用を想定しており、bashツールを利用してOAuth認証やAPI呼び出しを自動化します。主な利点は、Oura Ringの豊富な健康データにプログラムからアクセスできるようになり、パーソナライズされた健康管理や分析が可能になる点です。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/vellum-ai/vellum-assistant/tree/HEAD/skills/oura-setup

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Oura Ring 統合

ユーザーのOura Ringに接続し、Oura Cloud API V2を介して睡眠、心拍数、準備度、活動、その他の健康データを取得します。

前提条件

  • Oura Ring(Gen3またはRing4)とアクティブなOuraメンバーシップ(APIアクセスには月額6ドル必要)
  • Ouraアプリがインストールされ、リングとペアリング済みであること
  • https://cloud.ouraring.com のOura Cloudアカウント

セットアップ

1. 開発者アプリケーションの登録

ユーザーに https://developer.ouraring.com/applications にアクセスしてもらい、新しいアプリケーションを作成します:

  • 表示名: ユーザーが希望する統合用の名前
  • 説明: 統合の簡単な説明
  • 連絡先メール: ユーザーのメールアドレス
  • ウェブサイト: 有効なURL(個人のウェブサイトなど)
  • プライバシーポリシー / 利用規約: 有効なURL(必須項目ですが、個人アプリでは厳密に確認されません)
  • リダイレクトURI: http://localhost:3000/callback
  • スコープ: 必要なすべてのスコープを有効にします。推奨:personal, daily, heartrate, sleep, workout, spo2, stress, heart_health, session, ring_configuration

クライアントID と クライアントシークレット を保存します。

2. OAuthフローの実行

クライアントシークレットを assistant credentials prompt で安全に保存し、OAuthヘルパースクリプトを作成してユーザーのマシンで実行します:

#!/usr/bin/env python3
"""Oura Ring OAuth2ヘルパー — 認証コードをキャッチし、即座にトークンに交換します。"""
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs, urlencode
import urllib.request, json, webbrowser, ssl

CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
REDIRECT_URI = 'http://localhost:3000/callback'
SCOPES = 'email personal daily heartrate workout tag session spo2 ring_configuration stress heart_health'

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        parsed = urlparse(self.path)
        if parsed.path == '/':
            params = urlencode({
                'response_type': 'code', 'client_id': CLIENT_ID,
                'redirect_uri': REDIRECT_URI, 'scope': SCOPES, 'state': 'assistant'
            })
            self.send_response(302)
            self.send_header('Location', f'https://cloud.ouraring.com/oauth/authorize?{params}')
            self.end_headers()
        elif parsed.path == '/callback':
            code = parse_qs(parsed.query).get('code', [''])[0]
            if code:
                token_data = urlencode({
                    'grant_type': 'authorization_code', 'code': code,
                    'redirect_uri': REDIRECT_URI, 'client_id': CLIENT_ID,
                    'client_secret': CLIENT_SECRET,
                }).encode()
                try:
                    req = urllib.request.Request('https://api.ouraring.com/oauth/token',
                        data=token_data,
                        headers={'Content-Type': 'application/x-www-form-urlencoded'},
                        method='POST')
                    resp = urllib.request.urlopen(req, context=ssl.create_default_context())
                    result = json.loads(resp.read())
                    with open('/tmp/oura_tokens.json', 'w') as f:
                        json.dump(result, f, indent=2)
                    self.send_response(200)
                    self.send_header('Content-Type', 'text/html')
                    self.end_headers()
                    self.wfile.write(b'<html><body><h1>接続完了!このタブは閉じて構いません。</h1></body></html>')
                    print(f'\nトークンを /tmp/oura_tokens.json に保存しました')
                except Exception as e:
                    self.send_response(500)
                    self.end_headers()
                    self.wfile.write(f'トークン交換に失敗しました: {e}'.encode())
    def log_message(self, *a): pass

print('Oura認証のためにブラウザを開きます...')
webbrowser.open('http://localhost:3000')
HTTPServer(('localhost', 3000), Handler).serve_forever()

ユーザーのマシンで python3 /path/to/script.py を実行します(host_bash)。ユーザーがブラウザで認証すると、スクリプトがコードをキャッチし、1秒未満でトークンに交換します。

重要: 認証コードは約30秒で期限切れになります。ユーザーに手動でコードを貼り付けさせないでください — このスクリプトを使用して自動的にキャッチし、交換してください。

3. トークンの保存

OAuthフローの後、/tmp/oura_tokens.json からトークンを読み取り、保存します:

  • access_token — api.ouraring.com のAuthorizationヘッダー(Bearerプレフィックス)および `allowed_tools: [

関連スキル