Um Better Auth in einer Capacitor-App zu verwenden, installieren Sie better-auth client in Ihrem Web code, verweisen Sie es auf Ihren Better Auth-Server, fügen Sie die Capacitor Ursprünge hinzu ("capacitor://localhost auf iOS, https://localhost auf Android) zu trustedOrigins, und wechseln Sie von Cookies zu Bearer-Tokens mit dem bearer Plugin. E-Mail- und Passwort funktionieren über den SDK unverändert. Für Google und Apple erhalten Sie einen ID-Token mit einem nativen Plugin wie @capgo/capacitor-social-login und übergeben Sie es an authClient.signIn.social({ idToken }).
Diese Anleitung zeigt die Server- und Client-Konfiguration, die Token-Speicherung, den sozialen Anmeldevorgang, die Unterstützung von Enterprise-Anbietern und die Fehler, die Menschen erleben, wenn sie eine bessere Authentifizierung im Web in Capacitor 8 umsetzen.
Was ändert sich, wenn bessere Authentifizierung innerhalb von Capacitor
Ein Capacitor-App ist eine Web-App, die von einem lokalen Ursprung innerhalb eines nativen WebView ausgeliefert wird. Im Vergleich zu einer normalen Website sind drei Dinge anders:
| Thema | Auf einer Website | In einer Capacitor-App |
|---|---|---|
| Ursprung | https://app.example.com |
capacitor://localhost (iOS), https://localhost (Android) |
| Auth-Server | Oftmals funktionieren Cookies auf derselben Seite | Verschiedene Domäne, Drittanbieter-Cookies werden durch WKWebView blockiert |
| OAuth-Redirects | Ein vollständiger Seiten-Redirect ist in Ordnung | Der Redirect verlässt Ihre gebündelte App, Google blockiert WebViews |
Die Lösungen sind: Vertrauen Sie den Capacitor Ursprüngen, verwenden Sie Bearer-Tokens und verwenden Sie native Plugins für soziale Anmeldungen
Schritt 1: Konfigurieren Sie den Better Auth-Server
Diese Beispiele verwenden Hono, aber die Better Auth-Konfiguration ist für Express, Next.js Routen-Handler oder jede andere Laufzeit gleich
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 macht für Apple. Token von der native iOS-Schaltfläche tragen Ihre Bundle-ID als Zielgruppe, während Web- und Android-Token die Services-ID tragen. Better Auth verwendet diesen Feld, um beide anzunehmen
Montieren Sie den Handler und erlauben Sie CORS von den App-Ursprüngen. Expose die set-auth-token Überschrift, andernfalls sieht der Client den Bearer-Token nie:
// 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;
Starten bunx @better-auth/cli migrate (or generate für Ihre ORM) um die Tabellen zu erstellen.
Schritt 2: Erstellen Sie den Auth-Kunden in der App
bun add better-auth @capgo/capacitor-native-biometric
bunx cap sync
Speichern Sie den Sitzungstoken im Keychain oder Keystore und halten Sie eine Kopie im Speicher, damit der Client es synchron lesen kann.
// 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() vor dem Rendern Ihrer App authClient.getSession() aus dem entsprechenden Unterpfad (
import { authClient, loadSessionToken } from './auth-client';
await loadSessionToken();
const { data: session } = await authClient.getSession();
if (session) {
console.log('Signed in as', session.user.email);
}
Wenn Sie React, Vue, Svelte oder Solid verwenden, importieren Sie createAuthClient aus der entsprechenden Unterpfad ("better-auth/react, better-auth/vue, …) um die useSession Hook. Das fetchOptions bleiben gleich. Das setData und getData methods are native only. On web, fall back to cookies or sessionStorage mit Capacitor.isNativePlatform().
Schritt 3: E-Mail und Passwort
Kein Plugin erforderlich. Dies sind einfache HTTP-Anfragen.
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();
}
Für E-Mail-Verifizierung und Passwort-Restart sendet Better Auth Links, die eine URL öffnen. Klicken Sie callbackURL at a page on your domain that is also configured as an iOS Universal Link and Android App Link, so the link opens the app on phones and the website elsewhere.
Konfigurieren Sie Google wie in
"Wie Sie sich mit Google anmelden" unter __CAPGO_KEEP_0__ "Wie Sie sich mit Google anmelden" unter Capacitor, dann:
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;
}
Better Auth überprüft den Token gegen die Schlüssel von Google und den konfigurierten Client-Id, erstellt oder verknüpft den Benutzer und gibt eine Sitzung zurück. Der Bearer-Token landet im set-auth-token Header und Ihr onSuccess Hook speichert ihn.
Schritt 5: Native Apple-Authentifizierung
Konfigurieren Sie Apple wie in How to sign in with Apple using Capacitor. Generieren Sie einen Zufallswert, übermitteln Sie ihn an Apple und senden Sie denselben Wert an 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 teilt den Benutzernamen nur auf der ersten Autorisierung mit. Wenn Sie ihn auf dem Benutzerkonto haben möchten, aktualisieren Sie das Profil direkt nach der ersten Anmeldung mit result.profile.givenName und familyName.
Facebook folgt dem gleichen Muster. Auf iOS mit Limited Login erhalten Sie ein idTokensonst müssen Sie den Zugriffstoken übermitteln. Bessere Auth-Integration Seite besitzt die vollständige Facebook-Beispielanwendung.
Schritt 6: Okta, Auth0, Entra ID und andere OIDC-Anbieter
Bessere Auths genericOAuth Plugin liefert Hilfsmittel für Auth0, Okta, Keycloak und Microsoft Entra ID, sowie eine manuelle Konfiguration für jeden OIDC-Server. Im Web-Builder authClient.signIn.oauth2({ providerId }) funktioniert es wie auf jeder Website.
Auf iOS und Android benötigt der Flow den Systembrowser, da die Anbieter-Login-Seite nicht innerhalb Ihres WebView laden darf. Der funktionierende Muster lautet:
- Die App öffnet Ihre Better Auth-Anmeldeseite im Systembrowser (z.B.
SocialLogin.openSecureWindowoder einem in-app-Browser-Plugin). - Bessere Auth führt den OAuth-Tanz mit dem Anbieter durch und erstellt die Sitzung auf dem Server.
- Ihre Callback-Seite wandelt diese Sitzung in einen kurzlebigen, einmaligen Token um (Bessere Auth verfügt über ein
oneTimeTokenPlugin für diese Funktion) und leitet zu einer tiefen Verlinkung wiecom.example.app://auth?token=.... - Die App überprüft den einmaligen Token mit dem Auth-Client und erhält eine normale Bearer-Sitzung.
Das ist mehr Komponenten als der ID-Token-Übertrag. Wenn Sie nur Enterprise SSO benötigen und keine Benutzerdatenbank von Better Auth benötigen, ist das direkte Anmelden gegenüber dem Provider einfacher, siehe die Okta, Auth0 und Benutzerkennung Anleitungen.
Schritt 7: Schützen Sie Ihr API mit der Sitzung
Ihr eigener API kann die Sitzung aus dem Bearer-Token lesen, mit dem Server von 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));
});
Der Bearer-Plugin macht getSession accept Authorization: Bearer <token> wie es den Cookie annimmt.
Troubleshooting
| Problem | Ursache | Lösung |
|---|---|---|
Invalid origin oder 403 bei der Anmeldung |
Capacitor Ursprung nicht vertraut | Hinzufügen capacitor://localhost und https://localhost zu trustedOrigins |
| CORS-Fehler im WebView-Konsolenfenster | Der Server CORS listet die App-Ursprünge nicht auf | Hinzufügen sie zu Ihrem CORS-Middleware, zulassen Authorization |
Anmeldung erfolgreich, aber getSession keine null |
Übertragung von Cookies zwischen Domains | Verwenden Sie den Bearer-Plugin und senden Sie den Token |
set-auth-token ist immer null |
Header nicht sichtbar | Hinzufügen exposeHeaders: ['set-auth-token'] CORS |
Google: disallowed_useragent |
Authentifizierungsbildschirm in der WebView | Verwenden Sie native Authentifizierung und die idToken Übertragung |
| Google-ID-Token abgelehnt | Audience passt nicht zum konfigurierten Client-ID | Entschlüsseln Sie den Token mit SocialLogin.decodeIdToken und vergleichen Sie aud mit clientId |
| Apple-ID-Token abgelehnt auf iOS | Audience ist die Bundle-ID | Setzen Sie appBundleIdentifier im Apple-Anbieter |
| In der Apple-Anbieter | Verschiedene Nichtwiederholbarkeitswerte an Apple und Better Auth | Wert einmal generieren, wiederholen Sie ihn |
| Nach der App-Neustart verloren | Token nur im Speicher | Persistiere mit setData und laden Sie es vor der ersten Anfrage |
Die Mobilseite bereitstellen
Auth-Änderungen sind selten native. Vertrauenswürdige Ursprünge und Anbieter sind Serverkonfiguration, und der Client code ist TypeScript, daher können die meisten Fixes über code Live-Updates verschickt werden Capgo Live-Updates anstatt einer Store-Veröffentlichung. Sie benötigen nur eine neue Binärdatei, wenn Sie ein natives Plugin hinzufügen oder die URL-Schemas ändern.
Verwandte Anleitungen
- Authentifizierung in einer Capacitor-App hinzufügen vergleicht Better Auth mit Firebase, Supabase und gehosteten Identitätsanbietern
- Biometrische Authentifizierung in Capacitor-Apps für die Freischaltung einer gespeicherten Sitzung mit Face ID oder Fingerabdruck.
- Social Login-Plugin für die native Google-, Apple- und Facebook-Flüsse.