mcpField
O
oauth

oauth

github.com/val-town開発1041 回インストール5 週間前に更新
リポジトリ

oauth について

oauthは、Val Townのstd/oauthミドルウェアでHonoアプリにVal Townアカウントのログインを追加する方法を説明するスキルです。アプリ側でプロバイダーやセッションストアを設定せず、ログイン、ログアウト、セッションを管理できます。

主な機能

  1. 01OAuthミドルウェアでHono fetchハンドラーをラップ
  2. 02ログイン、コールバック、ログアウトのルートを追加
  3. 03認証済みユーザーのセッション情報を取得
  4. 04暗号化Cookieにセッションを保存

活用シーン

  1. 01HonoアプリにVal Townアカウントログインを追加
  2. 02現在のセッションに応じてルートを制限
  3. 03未認証時のリダイレクトや401応答を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/val-town/plugins --skill oauth

インストール後、Claude Code で/oauthを入力して読み込まれたか確認します。

詳細

OAuth(std/oauth)

Val Town では、std/oauth を使って設定不要の「Val Town でログイン」を利用できます。データベースの設定も、プロバイダーの設定も不要です。Hono の fetch ハンドラーをラップするだけで、ログイン、ログアウト、セッション管理を無料で利用できます。セッションは暗号化された Cookie に保存され、30 日間有効です。

これはVal Town アカウントへのログイン専用です。Google/GitHub/Slack などの OAuth については、third-party-integrations スキルをご覧ください。これらのフローはサービスごとに説明されています。

ログイン済みの独自ユーザーを作るのではなく、アプリをチーム内でのみ利用できるようにすることが目的であれば、val のアプリへのアクセスを制限するのがより簡単です。プラットフォームがコードの実行前にエンドポイントを制限するため、認証コードを書く必要はありません。restricted-access スキルをご覧ください。1 つの val に両方を適用しないでください。アクセス制限された val で oauthMiddleware も実行すると、訪問者は 2 回認証することになります。

インポート

import {
  getOAuthUserData,
  oauthMiddleware,
} from "https://esm.town/v/std/oauth/middleware.ts";

アプリのラップ

oauthMiddleware(handler) は Hono の fetch ハンドラーを受け取り、3 つの自動管理ルートを追加したラップ済みハンドラーを返します。

  • GET /auth/login — ログインフローを開始します
  • GET /auth/callback — ログインフローを完了します
  • POST /auth/logout — セッションをクリアします

ラップ済みハンドラーを val のデフォルトとしてエクスポートします。

import { Hono } from "npm:hono";
import { oauthMiddleware } from "https://esm.town/v/std/oauth/middleware.ts";

const app = new Hono();
app.onError((err) => Promise.reject(err));

app.get("/", (c) => c.text("hello"));

export default oauthMiddleware(app.fetch);

/auth/* ルートを自分で作成する必要はありません。ミドルウェアが追加します。アプリ内でこれらのルートを別の用途に使わないでください。

現在のユーザーの取得

どのルートからでも getOAuthUserData(rawRequest) を呼び出せます。Hono では、rawRequest は c.req.raw です。リクエストが認証済みの場合はセッションデータを返し、それ以外の場合は null を返します。

interface SessionData {
  user: {
    id: string;
    username: string | null;
    email: string | null;
    bio: string | null;
    tier: "free" | "pro" | null;
    type: "user" | "org";
    url: string;
    links: {
      self: string;
      profileImageUrl: string | null;
    };
  };
  accessToken: string; // Val Town API token (act on behalf of the user)
  refreshToken?: string;
  idToken?: string;
  expiresAt: number; // Unix timestamp (ms)
  isOrgMember?: boolean; // true if user belongs to this val's org
}
app.get("/", async (c) => {
  const session = await getOAuthUserData(c.req.raw);
  if (session?.user) {
    return c.html(
      `<p>Logged in as ${session.user.username}</p>` +
      `<form method="POST" action="/auth/logout"><button>Log out</button></form>`
    );
  }
  return c.html(`<a href="/auth/login">Log in with Val Town</a>`);
});

ルートの保護

組み込みの「ログイン必須」ヘルパーはありません。getOAuthUserData を確認してルートを保護し、セッションがない場合は 401 を返すか、/auth/login にリダイレクトします。

app.get("/dashboard", async (c) => {
  const session = await getOAuthUserData(c.req.raw);
  if (!session?.user) return c.redirect("/auth/login");
  return c.html(`<h1>Welcome ${session.user.username}</h1>`);
});

設定不要な項目

  • 環境変数は不要です。認証情報とリダイレクト URL はプラットフォームが処理します。
  • コールバック URL の設定は不要です。/auth/callback は自動的に設定されます。
  • セッションストアは不要です。セッションは暗号化された Cookie に保存されます。

変更の確認

OAuth を追加したら、保護されたルートに対して fetch_val_endpoint を呼び出し、未認証時にリダイレクトされるか、401 が返されることを確認します。ログインフロー全体を試すには実際のブラウザーセッションが必要であり、fetch_val_endpoint だけでは実行できません。ライブ URL を共有して、ユーザーにログインを試してもらってください。

コメント