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内で読み込まれないためです。どのパターンが機能するかは
- アプリはシステムブラウザでBetter AuthのサインインURLを開きます(例えば
SocialLogin.openSecureWindowまたはインアプリブラウザプラグイン) - Better AuthはプロバイダとOAuthダンスを実行し、サーバー上でセッションを作成します。
- コールバックページは、セッションを短期間の1回限りのトークンに変換し( Better Authにはこのための)
oneTimeTokenデープリンクにリダイレクトします。com.example.app://auth?token=.... - アプリは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__ライブアップデート
代わりにストアのリリースではなく。
- How to add authentication to a Capacitor app CapacitorアプリでBetter Authをよりよく使う方法
- Biometric authentication in Capacitor apps Better AuthとFirebase、Supabase、ホストされたIDプロバイダーとの比較。
- Capacitorアプリのバイオメトリック認証 Face IDまたは指紋で保存されたセッションをアンロックする。