認証

エージェント ネイティブ アプリは、アカウント優先の設計で認証に Better Auth を使用します。ユーザーは初回訪問時にアカウントを作成し、初日から実際の ID を取得します。

概要

認証は、認証サーバー プラグインの autoMountAuth(app) を介して自動的に構成されます。 3 つのモードがあります:

  • デフォルト: 送信メールの準備ができている場合は Better Auth の magic link を優先し、電子メール/パスワードをフォールバックとしてソーシャルプロバイダーとともに使用します。フォールバックを強制するには AUTH_MAGIC_LINK=0 を設定します。
  • リモート MCP OAuth: Claude コードや ChatGPT コネクタなどの MCP ホスト用の標準 OAuth 2.1。
  • カスタム: getSession コールバック経由で独自の認証を取得します。

ブラウザ フローはどこでも同じ Better Auth フローです。開発認証バイパスはありません。getSession() が local@localhost センチネルにフォールバックすることはありません。環境間で変わるのはサインアップの摩擦であり、ログインの壁ではありません:

環境 初回読み込み時の動作 メール認証
ローカル開発 使い捨て開発アカウントが自動的に作成され、サインインされます (ログインの壁なし) デフォルトでスキップされます (電子メールプロバイダーがない場合)
QA / プレビュー 通常のサインアップですが、テスターがメールを待つ必要がないように検証をスキップできます AUTH_SKIP_EMAIL_VERIFICATION=1 でスキップ
生産 通常の Better Auth サインアップ/ログイン 必須(電子メールプロバイダーが設定されている場合)

いくつかのフラグでこれを調整します。詳細は Environment Variables テーブルにあります:

  • AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT=1 — 自動開発アカウントではなく、ローカル開発の通常のサインアップ ページを使用します。
  • AUTH_DISABLED=true — ログイン/サインアップを完全にスキップし、すべてのリクエストを 1 人の共有ユーザーとして実行します (ローカル開発/プレビュー/デモのみ。実際のユーザーによる運用は決して行わないでください)。
  • AUTH_MODE=local — CLI/エージェント ID (開発ユーザー pnpm action が実行される) にのみ影響します。これはブラウザのログイン バイパスではありません**。

AUTH_DISABLED=true runs every request as one shared user. Use it only for local dev, previews, or demos — never in production with real users, where it would expose all data to anyone.

ローカル開発のサインイン

ループバックの開発サーバーでは、共有サインインページに Continue as local dev が最初に表示されます。実際の Better Auth 開発アカウントとセッションを作成または再利用するため、アプリの他の場所と同じ認証済みの経路を使います。

Show full sign in options を選ぶと、通常のサインアップ、パスワード、magic link、ソーシャルプロバイダーの選択肢が表示されます。ローカルセッションを作成できない場合は、標準認証を続けられるように、ページがこれらの選択肢を自動的に表示します。

この機能は、開発またはテスト中にブラウザが localhost、127.0.0.0/8、::1 を通じて接続した場合のみ利用できます。デプロイプレビューとホストされた本番環境では無効になります。これは認証のバイパスではありません。AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT=1 を設定すると、この機能を無効にして、ローカル開発で通常のサインインページを表示できます。

より良い認証 (デフォルト)

デフォルトでは、Better Auth が認証を強化します。以下を提供します:

  • magic link による登録とログイン(電子メール/パスワードをフォールバックとして使用)
  • ソーシャル プロバイダー (Google、GitHub、その他 35 社以上)
  • 役割と招待状を持つ組織
  • API および A2A アクセス用の JWT トークン
  • プログラマティック クライアントのベアラー トークンのサポート

Better Auth ルートは /_agent-native/auth/ba/* にマウントされます。このフレームワークは、下位互換性のあるエンドポイントも提供します。

  • GET /_agent-native/auth/session — 現在のセッションを取得
  • POST /_agent-native/auth/magic-link — magic link メールをリクエスト
  • POST /_agent-native/auth/login — 電子メール/パスワードによるログイン
  • POST /_agent-native/auth/register — アカウントを作成
  • POST /_agent-native/auth/logout — サインアウト

セッション Cookie のレルムはデプロイメント形状に従います。そのため、 データベース/オリジンは、分離されたままではないサインインとアプリを共有します:

展開形状 Cookie レルム
スタンドアロン アプリ スラッグ (APP_NAME、またはローカル開発のパッケージ名) によってアプリごとに分離されます。本番環境では安定した an プレフィックス
ワークスペース モード (AGENT_NATIVE_WORKSPACE=1) 1 つの共有レルム — ワークスペース アプリがオリジンとデータベースを共有する
カスタムの同じデータベースのサブドメイン COOKIE_DOMAIN で共有 Cookie をオプトインします
ファーストパーティがホストする (*.agent-native.com) アプリごとに分離された名前空間 (それぞれに独自の認証データベースがあります)。 COOKIE_DOMAIN=.agent-native.com はデフォルトでは無視されます

ファーストパーティがホストするアプリにはそれぞれ独自の認証データベースがあるため、クロスアプリ サインイン 共有 Cookie ではなく Cross-App SSO を経由します。 これらのデプロイでは、APP_NAME または派生可能なアプリ URL (APP_URL、URL) を提供する必要があります。 DEPLOY_PRIME_URL、または DEPLOY_URL);そうしないと、落ちるのではなく起動が失敗します 共有 an_session 名に戻ります。 1 つの認証データベースを意図的に共有する サブドメイン全体で、AGENT_NATIVE_SHARE_COOKIE_DOMAIN=1 を横に設定します COOKIE_DOMAIN.

QA アカウント

ローカル開発とテストでは、デフォルトでサインアップ電子メールの検証がスキップされるため、 受信トレイを待たずに実際の電子メール/パスワード アカウントを作成できます。強制する フローのテスト中にローカルで検証し、AUTH_SKIP_EMAIL_VERIFICATION=0 を設定します。

テスターが実際のアカウントを必要とするが、待つ必要がないホスト型 QA 環境の場合 電子メール配信時に次のように設定します。

AUTH_SKIP_EMAIL_VERIFICATION=1

このフラグが設定されている場合、電子メール/パスワードによるサインアップに電子メールは必要ありません 検証が行われ、サインアップ検証メールは送信されません。 QA のみに使用してください またはプレビュー環境で、+autoz アドレスを持つテスト アカウントに名前を付けます (name+autoz@example.com) なので、簡単に識別できます。

メール検証ポリシー

AUTH_SKIP_EMAIL_VERIFICATION はローカルおよび QA 向けの利便性であり、ホスト された環境では無視されます。本番環境を含むあらゆる環境でポリシーを明示するには、 設定で宣言します:

defineAppConfig({ auth: { requireEmailVerification: false } });

デプロイ用のエイリアスは AUTH_REQUIRE_EMAIL_VERIFICATION=0 です。宣言された値 は AUTH_SKIP_EMAIL_VERIFICATION と環境ごとの既定値の両方より優先されます。

false は未検証のアドレスをログイン資格情報として受け入れます。誰でも任意のメール アドレスを主張できるため、サインアップが別の方法ですでに制限されている場合にのみ 使用してください。メールプロバイダーのないデプロイで true を設定した場合は、検証 を配信できないため、代わりにパスワードによるサインアップが無効になります。

ソーシャル プロバイダー

ソーシャル ログインを有効にするために環境変数を設定します。 Better Auth はそれらを自動検出します:

# Google OAuth
GOOGLE_SIGN_IN_CLIENT_ID=your-low-scope-sign-in-client-id
GOOGLE_SIGN_IN_CLIENT_SECRET=your-low-scope-sign-in-client-secret

# 下位互換性のあるフォールバック、およびテンプレートのプロバイダー OAuth 認証情報
# Gmail やカレンダーなどの Google APIs に接続するもの。
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret

# GitHub OAuth
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret

createGoogleAuthPlugin() を使用するテンプレートには、「Google でサインイン」ページが表示されます。 Google OAuth コールバックは、ネイティブ アプリのモバイル ディープ リンクを自動的に処理します。

通常の場合は GOOGLE_SIGN_IN_CLIENT_ID / GOOGLE_SIGN_IN_CLIENT_SECRET を優先します アプリのログイン。そのクライアントは ID スコープのみを要求する必要があります。キープ 必要な製品統合用の GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET Google API スコープ、またはデプロイが分割されていない場合の従来のフォールバックとして まだ。メールおよびカレンダー スタイルのアプリは、独自のプロバイダー OAuth クライアントを使用する必要があるため、 広範な同意画面は汎用アプリのサインインには影響しません。

OAuth 状態署名

本番環境では OAUTH_STATE_SECRET をランダムな 32 文字以上の文字値に設定し、OAuth 状態エンベロープ (Google、Atlassian、Zoom) がサードパーティの秘密から独立した専用キーで HMAC 署名されるようにします。完全な要件と脅威モデルについては、Security — OAuth State Signing を参照してください。

組織

このフレームワークは、組み込みの組織システムを提供します。これは、organizations テーブルと org_members テーブルによってサポートされるフレームワーク独自の org/ モジュールであり、意図的に登録されていない Better Auth の組織プラグインではありません。すべてのアプリは以下をサポートしています:

  • 組織の作成
  • ロール (owner、admin、member) を持つメンバーを招待
  • アクティブな組織の切り替え
  • org_id 列による組織ごとのデータスコープ

アクティブな組織はセッション上で session.orgId として追跡され、組織を切り替えるとユーザーとエージェントに表示されるデータが変更されます。データ スコープ自体はスタックの下位で行われます。完全な session.orgId → AGENT_ORG_ID → SQL パイプラインとアクセス ガードについては、Security & Data Scoping を参照してください。 Multi-Tenancy ドキュメントでは、組織管理面について説明します。

静的 MCP ベアラー トークン

ACCESS_TOKEN と ACCESS_TOKENS はブラウザ認証ではないため、アプリを非公開にしません。これらは、OAuth フローを使用できない MCP/connect クライアントの静的ベアラー資格情報としてのみ残ります。

# 単一のトークン
ACCESS_TOKEN=my-secret-token

# 複数のトークン
ACCESS_TOKENS=token1,token2,token3

これらの変数を構成しても、訪問者に対してトークン ログイン ページが表示されることはありません。 Web サインインは、Better Auth またはカスタム getSession プロバイダーに留まります。

リモート MCP OAuth

すべてのアプリの MCP エンドポイントは、標準の保護された MCP リソースとして機能できます。 OAuth 対応クライアントは、リモート MCP URL のみで構成できます:

https://mail.agent-native.com/mcp

認証されていない MCP リクエストは、/.well-known/oauth-protected-resource を指す WWW-Authenticate チャレンジを返します。次に、クライアントはアプリの OAuth メタデータを検出し、パブリック クライアントを動的に登録し、アプリの認証ページを開き、アクセス トークンとリフレッシュ トークンのために認証コードを PKCE と交換します。

アクセス トークンは、設定されている場合は A2A_SECRET で署名され、それ以外の場合は BETTER_AUTH_SECRET で署名されます。これらは、署名されたユーザー/組織 ID と mcp:read、mcp:write、および/または mcp:apps スコープを保持し、正確な MCP リソース URL にオーディエンス バインドされています。リフレッシュ トークンはハッシュとしてのみ保存され、ローテーションされません。リフレッシュすると同じトークンが返され、リフレッシュ許可に固定の有効期限はありませんが、引き続き取り消すことができます。リクエストとリフレッシュのたびに、ユーザーがトークンの組織にまだ所属しているかを再確認するため、削除されたメンバーは次のリクエストで MCP へのアクセスを失います。ツール呼び出しと MCP アプリ リソースの読み取りは、サインインしているユーザーと同じ要求コンテキスト内で実行されます。埋め込まれた MCP アプリ iframe は、生の OAuth トークンを受信しません。

新しい MCP 認可コードとリフレッシュトークンは、発行時の所有者を記録します。トークン交換は、所有者に紐付いていない古い認可や所有者バインディングの不一致を invalid_grant で拒否し、古い所有者を推定しません。意図的なメールアドレス変更では、発行時の識別情報も更新されます。変更前のアドレスは無効になり、変更前にそのアドレス向けに署名されたアクセストークンと Connect トークンは拒否されます。アカウントがそのアドレスを再登録しない限り、新しいトークンも発行されません。OAuth クライアントは次回のリフレッシュ時に新しいアドレスのトークンを受け取ります。メンバーの退会処理は認可を取り消すか削除し、発行時のバインディングを別の人に移しません。

OAuth の所有者バインディング更新により、既存の OAuth 接続はすべて一度再接続する必要があります。更新の適用後は古い OAuth アクセストークンが拒否されます。所有者に紐付いていない古いリフレッシュトークンは invalid_grant を返し、未使用の古い認可コードは同意フローを最初からやり直す必要があります。新しく発行されたアクセストークンには、設定された有効期間とリクエストごとの所属確認が適用されます。この切り替えでは、従来の A2A 形式の mcp-connect 認証情報とアプリ間の A2A トークンは変更されません。古い OAuth 形式の Connect トークンを使う接続も再接続が必要です。

npx @agent-native/core@latest connect <url> --client claude-code は、この標準フローの URL 専用の MCP エントリを書き込みます。リモート MCP OAuth を実行できないクライアントの場合は、接続ページまたは npx @agent-native/core@latest connect --token <token> フォールバックを使用して、明示的なベアラー トークン エントリを書き込みます。

独自の認証を使用する

カスタム getSession コールバックを渡して、任意の認証プロバイダー (Clerk、Auth0、Firebase など) を使用します。

// server/plugins/auth.ts
import { createAuthPlugin } from "@agent-native/core/server";

export default createAuthPlugin({
  getSession: async (event) => {
    // Your custom auth logic here
    const session = await myAuthProvider.verify(event);
    if (!session) return null;
    return { email: session.email };
  },
  publicPaths: ["/api/webhooks"],
});

パブリック ワークスペース アプリ

ワークスペース アプリはデフォルトで内部にあります。匿名の訪問者がパブリックをロードできるようにするには サイトは管理ページを認証のままにし、ルート アクセスを宣言します apps/<id>/package.json:

{
  "agent-native": {
    "workspaceApp": {
      "audience": "public",
      "protectedPaths": ["/admin"]
    }
  }
}

逆の形状の場合は、デフォルトの内部対象ユーザーを維持し、公開のみを行います 特定の公開ページ:

{
  "agent-native": {
    "workspaceApp": {
      "publicPaths": ["/", "/share"]
    }
  }
}

publicPaths と protectedPaths はプレフィックス マッチングを使用するため、"/admin" も使用します は "/admin/users" をカバーします。これらの設定では、ページ ナビゲーションのみが開きます。フレームワーク ルート (/_agent-native/*) とカスタム API ルート (/api/*) には引き続き認証が必要です アプリがこれらのプレフィックスを明示的に追加しない限り createAuthPlugin({ publicPaths: [...] }).

セッション API

getSession(event) によって返されるセッション オブジェクトの形状は次のとおりです:

interface AuthSession {
  email: string; // User's email (primary identifier)
  userId?: string; // Better Auth user ID
  token?: string; // Session token
  name?: string; // Display name from the auth provider, when available
  image?: string; // Profile image from the auth provider, when available
  orgId?: string; // Active organization ID
  orgRole?: string; // Role in active org (owner/admin/member)
}

クライアントで、useSession() フックを使用します。

import {
  useSession,
} from "@agent-native/core/client/hooks"
function MyComponent() {
  const { session, isLoading } = useSession();
  if (isLoading) return <p>Loading...</p>;
  if (!session) return <p>Not signed in</p>;
  return <p>Hello, {session.email}</p>;
}

Return URL でサインイン

公開ページ (共有リンク、埋め込み、マーケティング ページ) を含むテンプレートには、多くの場合、匿名の閲覧者にサインインを求め、元のページに戻すページ内 CTA が必要です。フレームワークは、このための単一のエントリ ポイントを提供します。

/sign-in?return=<same-origin-path>

匿名のビューアがこの URL にアクセスすると、フレームワークのログイン ページが表示されます。サインインが成功すると (トークン、電子メール/パスワード、Google OAuth などの任意のフロー)、ブラウザーは return に戻ります。

return パラメータは 同一オリジン パスとして検証されます。ネットワーク パス参照 (//evil.com/...)、絶対 URL、data: / javascript: スキーム、および埋め込み制御文字はすべて / にフォールバックします。検証されたパスは、入力からエコーバックされるのではなく、URL パーサーから再構築されます。

React コンポーネントから:

import { Button } from "@/components/ui/button";

function SignInCta() {
  const onClick = () => {
    const ret = window.location.pathname + window.location.search;
    window.location.href = "/sign-in?return=" + encodeURIComponent(ret);
  };
  return <Button onClick={onClick}>Sign in</Button>;
}

ブックマークされたプライベート パス

通常のアプリページは、すべての訪問者に対して同一の非個人化された公開キャッシュ可能な SSR シェルを使用します。AppProviders がクライアントでセッションを確認し、/dashboard のような非公開パスでは、非公開 UI をマウントする前に匿名ユーザーを /sign-in?return=%2Fdashboard へリダイレクトします。サインイン後は /dashboard に戻ります。公開/SEO ルートには isPublicPath を、MCP 埋め込みトークンなど別の限定された認証方式を使う画面には sessionBypass を指定します。

そのシェルをどれだけキャッシュするかはデプロイメント全体の設定です — AGENT_NATIVE_SSR_CACHE については SSR Caching を参照してください。キャッシュを短縮または無効化しても変わるのは期間だけであり、SSR は引き続き Cookie を取り除いた匿名ブランチをレンダリングします。

舞台裏: Google OAuth

両方のフロー (明示的な /sign-in エントリポイントとブックマークされたパスのケース) は、OAuth 状態を通じてリターン URL をスレッド化します。状態はHMAC署名されているため、輸送中に偽造することはできません。コールバックでは、戻り値 URL はリダイレクトの前に同一オリジンとして再検証されます。そのため、漏洩した署名キーをオープン リダイレクト オラクルに変えることはできません。

テンプレートが /_agent-native/google/auth-url を直接ラップする場合 (例: 範囲を広げるためにメール テンプレートやカレンダー テンプレートがラップする場合)、?return=<path> クエリを受け入れ、encodeOAuthState のオプション オブジェクト形式を介して転送します。

const returnUrl = getQuery(event).return;
const state = encodeOAuthState({
  redirectUri,
  desktop,
  returnUrl: typeof returnUrl === "string" ? returnUrl : undefined,
});

デフォルトの /_agent-native/google/auth-url ルートはこれを自動的に行います。テンプレートでカスタム OAuth 処理が必要な場合にのみオーバーライドされます。

環境変数

変数 目的
BETTER_AUTH_SECRET Better Auth 用の署名キー (設定されていない場合は自動生成されます)
AUTH_SKIP_EMAIL_VERIFICATION QA/プレビュー環境で 1 に設定すると、電子メール/パスワードのサインアップが検証なしで続行できるようになります。ローカルの開発/テストはデフォルトでスキップされます
AUTH_REQUIRE_EMAIL_VERIFICATION 0 または 1 を設定すると、本番環境を含むあらゆる環境でパスワードサインアップの検証ポリシーを宣言できます。AUTH_SKIP_EMAIL_VERIFICATION より優先されます
AUTH_DISABLED ログイン/サインアップをスキップするには、true または 1 に設定します。すべてのリクエストは 1 人の共有ユーザーとして実行されます (ローカルの開発/プレビューのみ。実際のユーザーによる本番環境では使用できません)
AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT 新しい開発データベースでローカルホストの自動サインインを無効にするには、1 に設定します
AUTH_MODE local は、CLI/エージェント ID のみを解決します (開発ユーザー pnpm action が実行される)。ブラウザのログインをバイパスしない
COOKIE_DOMAIN 同じデータベースのサブドメイン間で共有セッション Cookie をオプトインします (Cookie Realms を参照)
AGENT_NATIVE_WORKSPACE 1 はワークスペース モードで実行されます。ワークスペース アプリ間で 1 つの共有セッション レルム
AGENT_NATIVE_SHARE_COOKIE_DOMAIN ファーストパーティのサブドメイン間で 1 つの認証データベースを共有するには、COOKIE_DOMAIN で設定します
OAUTH_STATE_SECRET OAuth 状態エンベロープ用の専用 HMAC キー (Security — OAuth State Signing を参照)
GOOGLE_SIGN_IN_CLIENT_ID アプリログインに優先される低スコープの Google OAuth クライアント ID
GOOGLE_SIGN_IN_CLIENT_SECRET アプリログイン用に優先される低スコープの Google OAuth シークレット
GOOGLE_CLIENT_ID 従来の Google ログイン フォールバック、および Google API 統合用のプロバイダー OAuth クライアント ID
GOOGLE_CLIENT_SECRET 従来の Google ログイン フォールバック、および Google API 統合用のプロバイダ OAuth シークレット
GITHUB_CLIENT_ID GitHub OAuth を有効にする
GITHUB_CLIENT_SECRET GitHub OAuth シークレット
ACCESS_TOKEN MCP/connect クライアントの静的ベアラー フォールバック。ブラウザ認証ではありません
ACCESS_TOKENS MCP/connect クライアントのカンマ区切りの静的ベアラー フォールバック。ブラウザ認証ではありません
A2A_SECRET JWT 署名付き A2A クロスアプリ ID 検証用の共有シークレット、および存在する場合は MCP OAuth アクセス トークン署名

既定で無効な Dispatch の desktop.workspace-sso フラグは利用可否だけを制御し、認証、署名、nonce、オリジン、コールバック、セッション、失効の検証は常に必須です。フラグが無効または読み取れない場合、Desktop はアプリごとのサインイン、サインアウト、設定を変更しません。 User-Agent の Canary マーカーは利用可否のヒントにすぎず、リモートアテステーションではありません。認証と認可はこれを信頼しません。 正規のホスト型アプリは、アプリごとの ID ハブ環境設定なしでパッケージ版 Desktop SSO Canary のリクエストを認識します。通常のブラウザは通常のアプリ別サインインを使います。セルフホスト型アプリで AGENT_NATIVE_IDENTITY_HUB_URL が必要なのは、残る明示的な Desktop 経路またはサーバー側フェデレーション経路だけです。安定版 Desktop は、後続リリースが別途承認されるまでブローカーを初期化しません。 Canary は匿名ユーザーのアプリサインイン画面への遷移を横取りしません。ユーザーは、アクティブな登録済みアプリについて Desktop の設定からワークスペースサインインを明示的に選択する必要があり、通常のアプリサインインが既定の経路のままです。

管理デプロイと招待

管理デプロイでは AUTH_SIGNUP=invited、ORG_CREATION=closed、AUTO_CREATE_DEFAULT_ORG=0 を設定します。管理デプロイガイドでブートストラップ管理者、招待、許可ドメインを確認してください。メンバー招待とドメインによる参加は別のルールです。

機械翻訳 — このページは自動的に翻訳されたもので、内容が完全に正確でない場合があります。 英語の原文を見る