8000 GitHub - g-kari/0g0-id · GitHub
[go: up one dir, main page]

Skip to content
g-kariPublic

About

No description, website, or topics provided.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

0g0-id

統合ID基盤(IdP)モノレポ — Google OAuth ラッパー + サービス管理基盤

Hono + Cloudflare Workers + D1 で構築した軽量な認証基盤です。

構成

id.0g0.xyz    — IdP コアAPI(認証・JWT・サービス管理)
user.0g0.xyz  — ユーザー向け画面(ログイン・プロフィール)
admin.0g0.xyz — 管理画面(サービス管理・ユーザー管理)
mcp.0g0.xyz   — MCP Worker(Claude Code連携)
0g0-id/
├── packages/shared/     # 共通ライブラリ(型定義・JWT・DB操作)
├── workers/
│   ├── id/              # IdP コアAPI
│   ├── user/            # ユーザー向け BFF + Astro MPA
│   │   └── frontend/    #   Astro フロントエンド
│   ├── admin/           # 管理画面 BFF + Astro MPA
│   │   └── frontend/    #   Astro フロントエンド
│   └── mcp/             # MCP Worker
└── migrations/          # D1 スキーマ

技術スタック

  • Hono — Webフレームワーク(API・BFF)
  • Astro — フロントエンド静的MPA(user/admin)
  • Tailwind CSS v4 — スタイリング
  • Cloudflare Workers — エッジランタイム
  • Cloudflare Workers Assets — 静的アセット配信(SPA fallback: not_found_handling = "single-page-application")
  • Cloudflare D1 — SQLiteベースDB
  • jose — ES256 JWT(WebCrypto)
  • Service Bindings — Worker間通信(ネットワーク経由なし)

セキュリティ設計

項目 実装
JWT署名 ES256 + JWKS(kid 付き)
OAuth state + PKCE (S256) 必須
Cookie __Host- prefix / HttpOnly / Secure / SameSite=Lax
CSRF Origin ヘッダー検証
リフレッシュトークン ローテーション + reuse detection(family 全失効)
DBSC Device Bound Session Credentials(端末公開鍵バインド + チャレンジ・レスポンス)
管理者権限 DB ロールベース + 初回ブートストラップ

ログのプライバシー

共有 logger は任意の例外・extra を出力せず、固定イベントと検証済みの HTTP / cleanup metadata だけを記録します。動的メッセージや他のログは対象外です。 互換性への影響と残る制限は Error log privacy を参照してください。

動作要件

  • Node.js: v22.23.4 以上(両 Astro frontend の Prism 依存を含む開発環境の要件。CI は v22.x)
  • npm: v11.x 以上(packageManager フィールドで npm@11.21.2 に固定)

セットアップ

1. 依存インストール

npm install

2. D1 データベース作成

wrangler d1 create 0g0-id-db
# 出力された database_id を workers/id/wrangler.toml に設定

3. マイグレーション実行

# ローカル D1 に全マイグレーション適用
cd workers/id
npx wrangler d1 migrations apply 0g0-id-db --local

# 本番 D1 に適用(push 前に必ず実行)
npm run migrate:id

⚠️ 新しいマイグレーションを追加して適用せずにデプロイすると D1_ERROR: no such column が本番で発生します。

4. ES256 鍵ペア生成

openssl ecparam -genkey -name prime256v1 -noout -out private.pem
openssl ec -in private.pem -pubout -out public.pem

5. シークレット設定

cd workers/id
npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put JWT_PRIVATE_KEY      # private.pem の内容
npx wrangler secret put JWT_PUBLIC_KEY       # public.pem の内容
npx wrangler secret put BOOTSTRAP_ADMIN_EMAIL

⚠️ 初回管理者で管理画面への新しいログインと管理者専用一覧の読み取りを確認したら、 BOOTSTRAP_ADMIN_EMAIL を削除してください。既存の管理者ロールは DB に保持されます。 削除の前提条件・即時デプロイへの注意・再投入の防止は 初回管理者の作成後 を参照してください。

6. フロントエンドビルド

cd workers/user/frontend && npm install && npm run build
cd workers/admin/frontend && npm install && npm run build

7. デプロイ

npm run deploy:id
npm run deploy:user    # フロントエンドビルド込み
npm run deploy:admin   # フロントエンドビルド込み
npm run deploy:mcp

開発

npm run dev:id     # :8787
npm run dev:user   # :8788
npm run dev:admin  # :8789
npm run typecheck  # 全ワークスペース型チェック

フロントエンド開発

cd workers/user/frontend && npm run dev    # Astro dev server
cd workers/admin/frontend && npm run dev   # Astro dev server

ローカル開発時は workers/id/.dev.vars にシークレットを記載します(.gitignore 済み):

GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
JWT_PRIVATE_KEY=...
JWT_PUBLIC_KEY=...
BOOTSTRAP_ADMIN_EMAIL=admin@example.com

BFF + SPA 構成

user/admin Worker は Hono(API)+ Astro MPA(UI) のハイブリッド構成です。

  • workers/{user,admin}/src/ — Hono API(認証・プロキシ)
  • workers/{user,admin}/frontend/ — Astro MPA(Astro static output)
  • ビルド成果物は workers/{user,admin}/dist/ に出力
  • Cloudflare Workers Assets がSPA配信を担当
  • run_worker_first で API/auth パスは Worker に、静的アセットは Assets に振り分け
  • not_found_handling = "single-page-application" で未知のパスは index.html にフォールバック

認証フロー

BFF フロー(user.0g0.xyz / admin.0g0.xyz)

ブラウザ → user.0g0.xyz/auth/login
  → state + PKCE 生成 → Cookie 保存
  → id.0g0.xyz/auth/login → Google 認可画面
  → id.0g0.xyz/auth/callback(Google コード受取)
  → ワンタイム認可コード発行
  → user.0g0.xyz/auth/callback
  → id への内部 API(Service Bindings)でコード交換
  → __Host- Cookie にトークン設定

外部サービスフロー(rss.0g0.xyz 等の非 BFF オリジン)

外部サービスが /auth/login を呼び出す場合は client_id が必須です。

ブラウザ → https://id.0g0.xyz/auth/login
              ?client_id=<CLIENT_ID>
              &redirect_to=<登録済みリダイレクトURI>
              &state=<STATE>
  → Google 認可画面
  → id.0g0.xyz/auth/callback
  → 認可コードを redirect_to に付与してリダイレクト
  → 外部サービスが /auth/exchange でトークン交換

client_id の必須ルール

呼び出し元 client_id 動作
BFF オリジン(user.0g0.xyz, admin.0g0.xyz, EXTRA_BFF_ORIGINS) 省略可 BFF フローで処理
外部サービス(非 BFF オリジン) 必須 省略すると 400 エラー
  • client_id なしで外部オリジンから呼び出すと 400 Bad Request — "client_id is required for external services"
  • client_id なしでログインするとユーザーとサービスの関係が記録されず、/api/users/me/connections(連携サービス一覧)に表示されない

API

/.well-known/jwks.json で ES256 公開鍵を公開しています。各サービスはこの JWKS を取得してローカルで JWT を検証できます。

詳細なエンドポイント一覧は .claude/rules/api.md を参照してください。

MCP Server

MCP 対応クライアント(Claude Code 等)から管理操作を実行するためのサーバーです。

  • エンドポイント: https://mcp.0g0.xyz/mcp
  • 認証: Bearer Token (ES256 JWT) + 管理者ロール必須

ツール一覧・認証方式・セットアップ方法は docs/mcp-server.md を参照してください。

DBSC(Device Bound Session Credentials)

BFF セッションに端末の公開鍵を結びつけ、チャレンジ・レスポンスで端末所有を証明する機構です。 機密操作(アカウント削除・SNS 連携解除等)をデバイスバインド済みセッションに限定できます。

  • Phase 1: デバイス公開鍵のバインド(ES256 JWK)
  • Phase 2: チャレンジ・レスポンス(nonce 発行 → Proof JWT 検証)
  • Phase 3: 機密操作の DBSC 必須化(DBSC_ENFORCE_SENSITIVE で制御)

詳細は docs/dbsc.md を参照。

デプロイ前 preflight チェック

npm run deploy:{id,user,admin} は wrangler deploy の前に preflight スクリプトを実行し、必須シークレットの登録漏れを検出する。

Worker 検査対象シークレット
id INTERNAL_SERVICE_SECRET_USER, INTERNAL_SERVICE_SECRET_ADMIN
user DBSC_ENFORCE_SENSITIVE
admin DBSC_ENFORCE_SENSITIVE

ローカルでは warn のみ(fail-open)。CI では PREFLIGHT_STRICT=1 を設定して必須化を推奨。

Cloudflare / GitHub 接続設定

docs/cloudflare-github-setup.md を参照してください。

コントリビューション

開発フロー・コミット規約・PR レビュー観点は CONTRIBUTING.md を参照してください。

連携サービスの Sub ID コピー

連携サービス画面の「コピー」で端末のクリップボードを使えない場合は、既に表示している同じ Sub ID の読み取り専用欄と手動コピー案内を表示します。追加のアクセス権は要求しません。失敗を成功とは表示せず、自動再試行やサービス解除はしません。詳しくは コピー復旧手順 を参照してください。

プロフィール保存時の下書き保持

保存ボタンを押した後も入力できます。先に送った内容の保存が完了しても、その間に編集した値は消しません。保存済みの名前・画像と未保存の入力を区別して案内し、残った変更はもう一度「保存」で送れます。同じページ内の保護であり、別タブ・別端末の同時更新は調停しません。詳しくは プロフィールの復旧と保存 を参照してください。

About

No description, website, or topics provided.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

0