Per usare Better Auth in un'app Capacitor, installa il better-auth client nel tuo web code, puntalo sul tuo server Better Auth, aggiungi gli Capacitor origini (capacitor://localhost su iOS, https://localhost On Android) per trustedOrigins, e passa dai cookie ai token bearer con il bearer plugin. Email e password funziona attraverso il SDK così com'è. Per Google e Apple, ottieni un token ID con un plugin nativo come @capgo/capacitor-social-login e passalo a authClient.signIn.social({ idToken }).
Questa guida mostra la configurazione del server e del client, lo storage dei token, l'accesso con account social, i provider aziendali e gli errori che le persone incontrano quando spostano un'app web Better Auth in Capacitor 8.
Cosa cambia quando Better Auth funziona all'interno di Capacitor
Un'app Capacitor è un'app web servita da un origin locale all'interno di un WebView nativo. Rispetto a un normale sito web, tre cose sono diverse:
| Argomento | Sul sito web | In un'app Capacitor |
|---|---|---|
| Origine | https://app.example.com |
capacitor://localhost (iOS), https://localhost (Android) |
| Auth server | Spesso lo stesso sito, i cookie funzionano comunque | Diverso dominio, i cookie di terze parti vengono bloccati da WKWebView |
| I redirect OAuth | Un redirect a pagina completa è accettabile | Il redirect lascia il tuo'applicazione bundle, Google blocca i WebViews |
Le soluzioni sono: fidarsi degli origini Capacitor, utilizzare token bearer e utilizzare plugin nativi per il login sociale
Passo 1: Configura il server di autenticazione Better Auth
Questa esempio utilizza Hono, ma la configurazione di Better Auth è la stessa per Express, gestori di route Next.js o qualsiasi altro runtime
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 Importa per Apple. I token dal foglio di iOS nativo portano il tuo ID bundle come destinatario, mentre i token web e Android portano l'ID Servizi. Better Auth utilizza questo campo per accettare entrambi
Monta il gestore e consenti CORS dai origini dell'applicazione. Espone il set-auth-token header, altrimenti il client non vede mai il token di autenticazione 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: Crea il client di autenticazione nell'app
Passo 2: Crea il client di autenticazione nell'app
bun add better-auth @capgo/capacitor-native-biometric
bunx cap sync
Memorizza il token di sessione nel Keychain o Keystore e conserva una copia in memoria affinché il client possa leggerlo in modo sincrono.
// 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() per ripristinare l'utente: authClient.getSession() per ripristinare l'utente:
import { authClient, loadSessionToken } from './auth-client';
await loadSessionToken();
const { data: session } = await authClient.getSession();
if (session) {
console.log('Signed in as', session.user.email);
}
Se utilizzi React, Vue, Svelte o Solid, importa createAuthClient , …) per ottenere ilbetter-auth/react, better-auth/vuePer ottenere i risultati migliori useSession hook. Il fetchOptions stay the same. Lo stesso. Il setData e getData metodi sono nativi solo. Sul web, ricadono su cookie o sessionStorage utilizzando Capacitor.isNativePlatform().
Step 3: Email e password
Nessun plugin necessario. Si tratta di chiamate HTTP semplici.
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();
}
Non è necessario alcun plugin. Questi sono semplici chiamate HTTP. callbackURL Per la verifica dell'indirizzo email e il reset della password, Better Auth invia link che aprono una URL. Indicizza
Passo 4: accesso con Google
Step 4: Accesso Google nativo context: How to sign in with Google using Capacitorpoi, quindi:
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;
}
Miglior Autenticazione verifica il token contro le chiavi di Google e l'ID del client configurato, crea o collega l'utente e restituisce una sessione. Il token di accesso arriva nel set-auth-token header e il tuo onSuccess hook lo memorizza.
Passo 5: Accesso nativo Apple
Configura Apple come descritto in Come effettuare l'accesso con Apple utilizzando Capacitor. Genera un valore nonce, passalo ad Apple e invia lo stesso valore a Miglior Autenticazione:
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 condivide solo il nome dell'utente alla prima autorizzazione. Se desideri che sia presente nel record utente, aggiorna il profilo subito dopo il primo accesso con result.profile.givenName e familyName.
Facebook segue lo stesso schema. Su iOS con Accesso Limitato ottieni un idTokenaltrove passa il token di accesso. Il Integrazione di Autenticazione Migliorata pagina ha l'esempio completo di Facebook.
Passo 6: Okta, Auth0, Entra ID e altri provider OIDC
Better Auth genericOAuth Il plugin fornisce ausili per Auth0, Okta, Keycloak e Microsoft Entra ID, oltre a una configurazione manuale per qualsiasi server OIDC. Nella build web, authClient.signIn.oauth2({ providerId }) funziona come su qualsiasi sito.
On iOS and Android the flow needs the system browser, because the provider login page must not load inside your WebView. The pattern that works:
- L'app apre la tua URL di accesso a Better Auth nel browser del sistema (ad esempio con)
SocialLogin.openSecureWindowo un plugin del browser integrato nell'app. - Autenticazione Migliorata esegue il ballo OAuth con il provider e crea la sessione sul server.
- Autenticazione Migliorata esegue il ballo di OAuth con il provider e crea la sessione sul server.
oneTimeTokenplugin per questo) e reindirizza a un link profondo comecom.example.app://auth?token=.... - L'App verifica il token a tempo di validità con il client di autenticazione e riceve una sessione bearer normale.
Questo comporta più parti in movimento rispetto alla cessione del token ID. Se hai bisogno solo di SSO aziendale e non hai bisogno della base di dati degli utenti di Better Auth, accedere direttamente al provider è più semplice, vedi i Okta, Auth0 e guida. guides.
Passo 7: Proteggere il tuo API con la sessione
Il tuo API può leggere la sessione dal token di autenticazione con il server API di Better Auth.
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));
});
Il plugin bearer fa getSession accept Authorization: Bearer <token> nella stessa maniera accetta il cookie.
Risolvere i problemi
| Problema | Causa | Soluzione |
|---|---|---|
Invalid origin o 403 all'accesso |
Capacitor non è stato riconosciuto come origine | Aggiungi capacitor://localhost e https://localhost a trustedOrigins |
| errore CORS nel console WebView | Il server CORS non elenca le origini dell'app | Aggiungile al tuo middleware CORS, consenti Authorization |
Accedi con successo ma getSession ritorna null |
Risiede su cookie tra domini | Utilizza il plugin bearer e invia il token |
set-auth-token è sempre null |
La testata non è esposta | Aggiungi exposeHeaders: ['set-auth-token'] utilizzare CORS |
Google: disallowed_useragent |
La pagina di accesso OAuth è caricata nel WebView | Utilizza l'accesso nativo e il idToken handoff |
| Token Google rifiutato | L'audience non corrisponde all'ID del client configurato | Decodifica il token con SocialLogin.decodeIdToken e confronta aud con clientId |
| Token ID Apple rifiutato su iOS | L'audience è l'ID del bundle | Imposta appBundleIdentifier nel fornitore Apple |
| nel provider Apple | Nonce diverso inviato a Apple e Better Auth | Nonce diverso inviato ad Apple e Better Auth |
| La sessione persa dopo il riavvio dell'app | Il token viene conservato solo in memoria | Persisti con setData e caricalo prima della prima richiesta |
La distribuzione del lato mobile
Auth changes are rarely native. Trusted origins and providers are server config, and the client code is TypeScript, so most fixes can ship through Capgo aggiornamenti in tempo reale Invece di una versione di store. Hai bisogno di un nuovo binario solo quando aggiungi un plugin nativo o cambi i schemi di URL.
Guida correlate
- Come aggiungere l'autenticazione a un'app Capacitor compara Better Auth con Firebase, Supabase e provider di identità ospitati.
- Come aggiungere l'autenticazione a un'app Capacitor per sbloccare una sessione memorizzata con Face ID o impronta digitale.
- plugin di accesso sociale per i flussi nativi di Google, Apple e Facebook.