Better Auth client plugin for Capacitor/Ionic mobile apps. Provides offline-first authentication with persistent storage, OAuth flow support, and session management.
@capacitor/preferences for offline access# Using pnpm
pnpm add better-auth-capacitor @capacitor/preferences
# Using npm
npm install better-auth-capacitor @capacitor/preferences
# Using yarn
yarn add better-auth-capacitor @capacitor/preferences
pnpm add @capacitor/app @capacitor/browser
pnpm add @capacitor/network
import { capacitorClient } from 'better-auth-capacitor'
import { createAuthClient } from 'better-auth/client'
const authClient = createAuthClient({
baseURL: 'https://api.example.com',
plugins: [
capacitorClient({
scheme: 'myapp', // For OAuth deep links
storagePrefix: 'better-auth',
}),
],
})
interface CapacitorClientOptions {
/**
* Prefix for storage keys
* @default 'better-auth'
*/
storagePrefix?: string
/**
* Prefix(es) for server cookie names to filter
* Prevents infinite refetching when third-party cookies are set
* @default 'better-auth'
*/
cookiePrefix?: string | string[]
/**
* App scheme for deep links (e.g., 'myapp')
* Used for OAuth callback URLs
*/
scheme?: string
/**
* Disable session caching
* @default false
*/
disableCache?: boolean
}
For making authenticated API requests outside of Better Auth:
import { getCapacitorAuthToken } from 'better-auth-capacitor'
const token = await getCapacitorAuthToken({
storagePrefix: 'better-auth',
cookiePrefix: 'better-auth',
})
if (token) {
fetch('https://api.example.com/data', {
headers: {
Authorization: `Bearer ${token}`,
},
})
}
If you have custom authentication endpoints that don’t use the Better Auth client (e.g., dev login, server-side auth), you can manually store the session token:
import { clearCapacitorAuthToken, setCapacitorAuthToken } from 'better-auth-capacitor'
// After custom login endpoint
const response = await fetch('/api/auth/custom-login', {
method: 'POST',
body: JSON.stringify({ email: 'user@example.com' }),
})
const data = await response.json()
// Store the token in Capacitor Preferences
await setCapacitorAuthToken({
token: data.session.token,
expiresAt: data.session.expiresAt, // Optional, defaults to 7 days
storagePrefix: 'better-auth',
cookiePrefix: 'better-auth',
})
// Now getSession() will work correctly
const session = await authClient.getSession()
// To clear the token (custom logout)
await clearCapacitorAuthToken({ storagePrefix: 'better-auth' })
Track which method the user last used to sign in:
import { capacitorClient, lastLoginMethodClient } from 'better-auth-capacitor'
import { createAuthClient } from 'better-auth/client'
const authClient = createAuthClient({
baseURL: 'https://api.example.com',
plugins: [
capacitorClient({ scheme: 'myapp' }),
lastLoginMethodClient({ storagePrefix: 'better-auth' }),
],
})
// Get the last used login method
const lastMethod = await authClient.getLastUsedLoginMethod()
// Returns: 'google', 'github', 'email', 'passkey', etc.
// Check if a specific method was last used
const wasGoogle = await authClient.isLastUsedLoginMethod('google')
// Clear the stored method
await authClient.clearLastUsedLoginMethod()
The capacitorClient plugin adds these actions to your auth client:
// Get stored cookie string for manual fetch requests
const cookie = await authClient.getCookie()
// Get cached session data for offline use
const session = await authClient.getCachedSession()
// Clear all stored auth data
await authClient.clearStorage()
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
The plugin expects an /expo-authorization-proxy endpoint on your server that:
Example implementation with Better Auth:
// server/api/expo-authorization-proxy.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event)
const authorizationURL = query.authorizationURL as string
const oauthState = query.oauthState as string
// Redirect to the OAuth provider
return sendRedirect(event, authorizationURL)
})
When initiating OAuth sign-in, use relative callback URLs:
await authClient.signIn.social({
provider: 'google',
callbackURL: '/auth/callback', // Will become myapp://auth/callback
})
import { isNativePlatform } from 'better-auth-capacitor'
if (isNativePlatform()) {
// Running in Capacitor native app
}
else {
// Running in web browser
}
| Export | Description |
|---|---|
capacitorClient(options?) |
Main Better Auth plugin for Capacitor |
getCapacitorAuthToken(options?) |
Get bearer token from storage |
setCapacitorAuthToken(options) |
Store token for custom auth endpoints |
clearCapacitorAuthToken(options?) |
Clear stored auth token |
isNativePlatform() |
Check if running in Capacitor native app |
setupCapacitorFocusManager() |
Set up app focus tracking |
setupCapacitorOnlineManager() |
Set up network connectivity tracking |
better-auth-capacitor/plugins)| Export | Description |
|---|---|
lastLoginMethodClient(config?) |
Track last used login method |
| Export | Description |
|---|---|
normalizeCookieName(name) |
Normalize cookie name for storage |
getCookie(cookie) |
Convert stored cookies to header string |
getSetCookie(header, prevCookie?) |
Merge new cookies with existing |
hasBetterAuthCookies(header, prefix) |
Check if header contains auth cookies |
parseSetCookieHeader |
Re-exported from better-auth/cookies |
better-auth >= 1.0.0@capacitor/core >= 6.0.0@capacitor/preferences >= 6.0.0@capacitor/app >= 6.0.0 (for OAuth deep links, focus manager)@capacitor/browser >= 6.0.0 (for OAuth browser opening)@capacitor/network >= 6.0.0 (for online manager)MIT
We use cookies
We use cookies to analyze traffic and improve your experience. You can accept or reject analytics cookies.