メインコンテンツにジャンプします

How to Use Better Auth in Capacitor Apps (2026 Guide)

Use Better Auth in a Capacitor 8 app: trusted origins, bearer tokens instead of cookies, email and password, native Google and Apple sign-in, and fixes.

著者クレジット

マーティン・ドナディュー

ライター

Valeria

Reviewer

Jordan

Editor

How to Use Better Auth in Capacitor Apps (2026 Guide)

To use Better Auth in a Capacitor app, install the better-auth クライアントをあなたのウェブ code に追加し、Better Auth サーバーに接続し、Capacitor のオリジンを追加してください。capacitor://localhost iOSの場合、 https://localhost Androidの場合、 trustedOrigins, bearer プラグイン。メールとパスワードはSDKを通じてそのまま機能します。GoogleやAppleの場合は、ネイティブプラグインを使用してIDトークンを取得します。 @capgo/capacitor-social-login EmailとパスワードはCapacitorアプリでそのまま機能します。GoogleとAppleの場合、ネイティブプラグインを使用してIDトークンを取得し、 authClient.signIn.social({ idToken }).

This guide shows the server and client setup, token storage, social sign-in, enterprise providers, and the errors people hit when they move a Better Auth web app into Capacitor 8.

What changes when Better Auth runs inside Capacitor

A Capacitor app is a web app served from a local origin inside a native WebView. Compared to a normal website, three things are different:

トピック ウェブサイト In a Capacitor app
オリジン https://app.example.com capacitor://localhost iOS https://localhost Android
認証サーバ 通常のサイトの場合、Cookieは機能します。 異なるドメインの場合、WKWebViewでは第三者Cookieがブロックされます。
OAuth リダイレクト フルページリダイレクトは問題ありません リダイレクトはバンドルされたアプリから外に出ます。Google は WebView をブロックします

修正方法は、Capacitor のオリジンを信頼すること、Bearer トークンを使用すること、そしてソーシャルログイン用のネイティブ プラグインを使用することです。

ステップ 1: Better Auth サーバを設定する

この例では Hono を使用していますが、Better Auth の設定は Express、Next.js ルート ハンドラー、または他の実行環境でも同じです。

bun add better-auth hono
// auth.ts
import { betterAuth } from 'better-auth';
import { bearer } from 'better-auth/plugins';
import { db } from './db'; // your Drizzle, Prisma, Kysely or pg instance

export const auth = betterAuth({
  baseURL: process.env.BETTER_AUTH_URL, // https://auth.example.com
  database: db,
  emailAndPassword: {
    enabled: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_WEB_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    },
    apple: {
      clientId: process.env.APPLE_SERVICE_ID as string,
      clientSecret: process.env.APPLE_CLIENT_SECRET as string,
      appBundleIdentifier: process.env.APPLE_BUNDLE_ID as string, // com.example.app
    },
  },
  trustedOrigins: [
    'capacitor://localhost', // iOS WebView
    'https://localhost', // Android WebView (androidScheme https, the default)
    'https://app.example.com', // your web build
    'https://appleid.apple.com',
  ],
  plugins: [bearer()],
});

appBundleIdentifier Apple に関することは重要です。ネイティブ iOS シートから取得したトークンには、バンドル ID がアウディエンスとして含まれます。Web と Android から取得したトークンには Services ID が含まれます。Better Auth はこのフィールドを使用して両方を受け入れることができます。

ハンドラーをマウントし、アプリのオリジンから CORS を許可する。Expose を set-auth-token ヘッダーを公開しないと、クライアントは Bearer トークンを表示できません:

// server.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { auth } from './auth';

const app = new Hono();

app.use(
  '/api/auth/*',
  cors({
    origin: ['capacitor://localhost', 'https://localhost', 'https://app.example.com'],
    allowHeaders: ['Content-Type', 'Authorization'],
    allowMethods: ['GET', 'POST', 'OPTIONS'],
    exposeHeaders: ['set-auth-token'],
    credentials: true,
  }),
);

app.on(['GET', 'POST'], '/api/auth/*', (c) => auth.handler(c.req.raw));

export default app;

Run bunx @better-auth/cli migrate (or generate または (または、開発者がアプリを構築する方法を比較するのに役立ちます。

Step 2: Capgoアプリで認証クライアントを作成する

bun add better-auth @capgo/capacitor-native-biometric
bunx cap sync

セッショントークンをKeychainまたはKeystoreに保存し、メモリにコピーして、クライアントが同步で読み取れるようにする

// auth-client.ts
import { createAuthClient } from 'better-auth/client';
import { NativeBiometric } from '@capgo/capacitor-native-biometric';

const TOKEN_KEY = 'session.token';
let sessionToken = '';

export async function loadSessionToken() {
  try {
    const { value } = await NativeBiometric.getData({ key: TOKEN_KEY });
    sessionToken = value;
  } catch {
    sessionToken = '';
  }
}

async function saveSessionToken(token: string) {
  sessionToken = token;
  if (token) {
    await NativeBiometric.setData({ key: TOKEN_KEY, value: token });
  } else {
    await NativeBiometric.deleteData({ key: TOKEN_KEY }).catch(() => {});
  }
}

export const authClient = createAuthClient({
  baseURL: 'https://auth.example.com',
  fetchOptions: {
    auth: {
      type: 'Bearer',
      token: () => sessionToken,
    },
    onSuccess: async (ctx) => {
      const token = ctx.response.headers.get('set-auth-token');
      if (token) await saveSessionToken(token);
    },
  },
});

export async function clearSession() {
  await saveSessionToken('');
}

Call await loadSessionToken() Capgoアプリがレンダリングする前に authClient.getSession() ユーザーを復元するには

import { authClient, loadSessionToken } from './auth-client';

await loadSessionToken();
const { data: session } = await authClient.getSession();
if (session) {
  console.log('Signed in as', session.user.email);
}

React、Vue、Svelte、またはSolidを使用する場合、次のコードをインポートします createAuthClient 対応するサブパスからbetter-auth/react, better-auth/vue… useSession hookを取得します fetchOptions hookは同じままです setData and getData and sessionStorage using Capacitor.isNativePlatform().

Step 3: メールとパスワード

プラグインは必要ありません。HTTPコールは通常のものです。

import { authClient, clearSession } from './auth-client';

export async function signUp(email: string, password: string, name: string) {
  const { data, error } = await authClient.signUp.email({ email, password, name });
  if (error) throw new Error(error.message);
  return data;
}

export async function signIn(email: string, password: string) {
  const { data, error } = await authClient.signIn.email({ email, password });
  if (error) throw new Error(error.message);
  return data;
}

export async function signOut() {
  await authClient.signOut();
  await clearSession();
}

メールアカウントの確認とパスワードのリセットの場合、Better Authはリンクを送信します。リンクをクリックするとURLが開きます。 callbackURL Step 4: ネイティブ Google サインイン

Configure Google as described in

How to sign in with Google using __CAPGO_KEEP_0__ How to sign in with Google using Capacitor, then:

import { SocialLogin } from '@capgo/capacitor-social-login';
import { authClient } from './auth-client';

await SocialLogin.initialize({
  google: {
    webClientId: 'WEB_CLIENT_ID.apps.googleusercontent.com',
    iOSClientId: 'IOS_CLIENT_ID.apps.googleusercontent.com',
    mode: 'online', // Better Auth needs the idToken, offline mode only returns a code
  },
});

export async function signInWithGoogle() {
  const { result } = await SocialLogin.login({ provider: 'google', options: {} });

  if (result.responseType !== 'online' || !result.idToken) {
    throw new Error('Google did not return an ID token');
  }

  const { data, error } = await authClient.signIn.social({
    provider: 'google',
    idToken: {
      token: result.idToken,
      accessToken: result.accessToken?.token,
    },
  });
  if (error) throw new Error(error.message);
  return data;
}

Step 3: メールとパスワード認証 set-auth-token Step 4: Googleサインイン onSuccess Step 3: メールとパスワード認証

ステップ 5:ネイティブ Apple サインイン

AppleをCapacitorアプリで使用するための認証設定を参照してください。 How to sign in with Apple using CapacitorAppleからnonceを生成し、Capacitorアプリに送信するには、nonceをAppleに渡し、同じ値をBetter Authに送信します。

import { SocialLogin } from '@capgo/capacitor-social-login';
import { authClient } from './auth-client';

export async function signInWithApple() {
  const nonce = crypto.randomUUID();

  const { result } = await SocialLogin.login({
    provider: 'apple',
    options: { scopes: ['email', 'name'], nonce },
  });

  if (!result.idToken) throw new Error('Apple did not return an ID token');

  const { data, error } = await authClient.signIn.social({
    provider: 'apple',
    idToken: {
      token: result.idToken,
      nonce,
      accessToken: result.accessToken?.token,
    },
  });
  if (error) throw new Error(error.message);
  return data;
}

Apple は初回の認証のみユーザーの名前を共有します。ユーザー情報に名前を表示したい場合は、初回のサインイン後にプロフィールを更新してください。 result.profile.givenName と familyName.

Facebookは同じパターンを採用しています。iOSのLimited Loginでは、 idTokenアクセストークンを、ここではそれを渡します。 Capacitorアプリでより良い認証統合 Facebook の例が完全に含まれます。

ステップ 6: Okta、Auth0、Entra ID、およびその他の OIDC プロバイダー

Better Authの genericOAuth Capacitorアプリで使うためのBetter Authの使い方 authClient.signIn.oauth2({ providerId }) Webビルドでは

iOSとAndroidでは、システムブラウザが必要です。プロバイダーのログインページはWebView内で読み込まれないためです。どのパターンが機能するかは

  1. アプリはシステムブラウザでBetter AuthのサインインURLを開きます(例えば SocialLogin.openSecureWindow またはインアプリブラウザプラグイン)
  2. Better AuthはプロバイダとOAuthダンスを実行し、サーバー上でセッションを作成します。
  3. コールバックページは、セッションを短期間の1回限りのトークンに変換し( Better Authにはこのための) oneTimeToken デープリンクにリダイレクトします。 com.example.app://auth?token=....
  4. アプリは1回限りのトークンを認証クライアントと検証し、通常のベアラー セッションを受け取ります。

IDトークン ハンドオフよりも多くのパーツが動きます。企業SSOのみが必要で、Better Authのユーザー データベースが必要でない場合は、プロバイダに直接サインインするのが簡単です。詳細は Okta, Auth0 と ログインID ガイド

Step 7: セッションで保護するためにあなたの API を

あなたの API は、Bearer トークンからセッションを読み取ることができます。Better Authのサーバー API:

import { Hono } from 'hono';
import { auth } from './auth';

const api = new Hono();

api.get('/me/orders', async (c) => {
  const session = await auth.api.getSession({ headers: c.req.raw.headers });
  if (!session) return c.json({ error: 'unauthorized' }, 401);
  return c.json(await listOrders(session.user.id));
});

Bearer プラグインは getSession 受け入れる Authorization: Bearer <token> 同じ方法でクッキーを受け入れる

トラブルシューティング

問題 原因 修正
Invalid origin または403のサインイン Capacitorのオリジンが信頼されていません 追加 capacitor://localhost and https://localhost to trustedOrigins
と サーバー CORS はアプリの起源をリストしていません。 CORSミドルウェアに追加して、許可 Authorization
CORSエラーがWebViewコンソールに表示される getSession returns null CORSミドルウェアに追加して許可 サインインは成功しますが、
set-auth-token 常に null ヘッダーが公開されていません。 Add exposeHeaders: ['set-auth-token'] CORS
Headerが公開されていない disallowed_useragent 追加 CORS に対して idToken Google:
WebView内で読み込まれたOAuthページ ネイティブのサインインと ハンドオフ SocialLogin.decodeIdToken Google IDトークンが拒否された aud Capgo clientId
Capacitor Live Update Cloudflare appBundleIdentifier GitHub
code API SDK
CLI npm bun setData リクエストの最初に読み込む

Capacitorアプリの使用方法

Auth の変更はほとんどがネイティブではありません。信頼できるオリジンとプロバイダーはサーバー設定であり、クライアント側は code のため、ほとんどの修正は TypeScript を通じて配信できます。 Authの変更はほとんどがネイティブではない。信頼できるオリジンとプロバイダーはサーバー設定であり、クライアントCapgoはTypeScriptなので、ほとんどの修正はLive Updateを通じて配信できる。 __CAPGO_KEEP_0__ライブアップデート

Capacitor アプリ用の即時更新

ウェブ層のバグが生じた場合、 Capgo を通じて修正を配信するのではなく、数日間待ってアプリストアの承認を待つのではなく、ユーザーはバックグラウンドで更新を受け取り、ネイティブの変更は通常のレビュー経路に従う

マーティンから人間のサポート

スタートする

最新のブログ記事

Capgo は、プロフェッショナルなモバイルアプリを作成するために必要な最良の洞察を提供します。