메인 콘텐츠로 건너뛰기

Capacitor 앱에서 더 나은 인증 방법 사용하기 (2026년 가이드)

Capacitor 앱에서 Capacitor 8을 사용하여 신뢰할 수 있는 원본, 토큰 대신 쿠키, 이메일 및 비밀번호, 네이티브 구글 및 애플 로그인, 및 수정 사항을 사용하세요.

기사 저자

마틴 도나디유

작가

발레리아

리뷰어

조던

편집자

Capacitor 앱에서 Capacitor Better Auth를 사용하는 방법 (2026 년 안내서)

Capacitor Better Auth를 사용하려면 Capacitor 앱에 Better Auth 패키지를 설치하세요. better-auth 클라이언트를 웹 code에 추가하고, Better Auth 서버를 지정한 후, Capacitor 출처를 추가합니다.capacitor://localhost iOS에서 https://localhost 안드로이드)에서 사용하는 방법을 trustedOrigins인증을 더 잘 사용하는 Capacitor 앱을 만드는 방법 bearer 이 가이드는 서버와 클라이언트 설정, 토큰 저장, 소셜 로그인, 기업 제공자, 그리고 Better Auth 웹 앱을 SDK 8로 이동할 때 발생하는 오류를 보여줍니다. @capgo/capacitor-social-login Better Auth가 __CAPGO_KEEP_0__ 내에서 작동할 때 변경되는 사항은? authClient.signIn.social({ idToken }).

Capacitor 앱은 로컬 오리진 내의 네이티브 WebView에서 웹 앱을 제공합니다. 일반적인 웹사이트와 비교했을 때 세 가지 차이점이 있습니다.

Capacitor 내에서 Better Auth가 실행될 때는 어떤 변화가 생기는가

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:

Topic 오리진 Capacitor 앱에서 사용하는 Capacitor
Origin https://app.example.com capacitor://localhost (iOS), https://localhost (안드로이드)
인증 서버 동일한 사이트일 경우, 쿠키만 사용하면 됩니다. 다른 도메인일 경우, WKWebView에서 세션 쿠키가 차단됩니다.
OAuth 리다이렉트 전체 페이지 리다이렉트는 문제가 없습니다. 리다이렉트가 앱을 벗어나면 Google에서 WebView를 차단합니다.

해결 방법은 Capacitor 도메인에 대한 신뢰를 설정하고, Bearer 토큰을 사용하고, 소셜 로그인에 대한 네이티브 플러그인을 사용하는 것입니다.

Step 1: Better Auth 서버를 구성하세요.

이 예제에서는 Hono를 사용하고 있지만, 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가 대상으로 설정되며, 웹 및 안드로이드 토큰은 Services ID를 대상으로 설정합니다. Better Auth는 이 field를 사용하여 두 가지를 모두 지원합니다.

핸들러를 마운트하고 앱의 도메인에서 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 ORM을 사용하여 테이블을 생성하세요.

2단계: 앱에서 인증 클라이언트를 생성하십시오

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

(or

// 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() for your ORM) to create the tables. authClient.getSession() Capgo 앱에서 인증 클라이언트를 만들기 위한 2단계:

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를 사용하는 경우 import createAuthClient Appflow Migration Step2. Call Capgo before your app renders, thenbetter-auth/react, better-auth/vuebefore your app renders, then useSession hook. fetchOptions same. The setData and getData web, cookies or 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 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.

Step 4: 네이티브 구글 로그인

구글을 Capgo 설명서에 따라 설정하십시오. Capacitor그런 다음:

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는 Google의 키와 구성된 클라이언트 ID와 일치시켜 사용자를 생성하거나 연결하고 세션을 반환합니다. set-auth-token Bearer 토큰은 onSuccess 헤더에 도착하고

hook에서 저장됩니다.

5. 네이티브 애플 로그인 How to sign in with Apple using Capacitor__CAPGO_KEEP_0__

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 and familyName.

Facebook은 동일한 패턴을 따릅니다. iOS에서 Limited Login을 사용하면 idToken을 받고, 그 외의 경우에는 액세스 토큰을 전달합니다. Capacitor 앱에서 더 나은 인증 통합 방법 더 나은 인증 통합 페이지에는 전체 Facebook 예제가 있습니다.

6단계: Okta, Auth0, Entra ID 및 기타 OIDC 제공자

Capacitor 앱에서 더 나은 인증 genericOAuth 더 나은 인증 플러그인은 Auth0, Okta, Keycloak 및 Microsoft Entra ID와 같은 OIDC 서버에 대한 수동 구성도 지원합니다. authClient.signIn.oauth2({ providerId }) 웹 빌드에서는 웹 사이트와 같이 작동합니다.

iOS 및 Android에서 흐름은 시스템 브라우저가 필요합니다. 제공자 로그인 페이지는 WebView 내에서 로드되지 않아야 합니다.

  1. 작동하는 패턴은 다음과 같습니다: SocialLogin.openSecureWindow 앱은 시스템 브라우저(예:
  2. 또는 내 앱 브라우저 플러그인)에서 더 나은 인증 로그인 URL을 열어줍니다.
  3. 더 나은 인증은 제공자와 OAuth 댄스를 실행하고 서버에서 세션을 생성합니다. oneTimeToken 콜백 페이지는 세션을 더 짧은 수명 한 번만 사용할 수 있는 토큰으로 변환하고 (더 나은 인증은 이에 대한 플러그인을 제공합니다) com.example.app://auth?token=....
  4. 앱은 일회용 토큰을 인증 클라이언트와 확인하고 일반적인 보유자 세션을 받습니다.

ID 토큰 전달보다 더 많은 움직임이 있습니다. 기업 SSO만 필요하고 Better Auth의 사용자 데이터베이스가 필요하지 않다면, 제공자에 직접 로그인하는 것이 더 단순합니다. 자세한 내용은 Okta, Auth0 그리고 로그인 ID 을 참조하세요.

Step 7: API을 보호하기 위해 세션을 사용하십시오

Your own 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));
});

보유자 플러그인은 getSession accept Authorization: Bearer <token> 을 동일한 방식으로 쿠키를 수락하는 것과 같습니다.

문제 해결

문제 원인 해결
Invalid origin 로그인 시 403 오류 Capacitor 원본이 신뢰되지 않음 추가 capacitor://localhost 그리고 https://localhost 까지 trustedOrigins
CORS 오류가 WebView 콘솔에 나타남 서버 CORS가 앱 원본을 목록에 포함하지 않음 그들을 CORS 미들웨어에 추가하고 허용 Authorization
로그인 성공하지만 getSession 반환 null 도메인 간 쿠키를 사용하는 Bearer 플러그인을 사용하여 토큰을 전송
set-auth-token 항상 null 헤더가 공개되지 않음 추가 exposeHeaders: ['set-auth-token'] CORS
Google: disallowed_useragent 웹뷰 내에 로드된 OAuth 페이지 자연스러운 로그인과 idToken 전환
구글 ID 토큰 거부 구독자 ID가 구성된 클라이언트 ID와 일치하지 않습니다. 토큰을 해독하고 SocialLogin.decodeIdToken 그리고 비교 aud 와 clientId
iOS에서 Apple ID 토큰이 거부되었습니다. 구독자 ID는 앱의 패키지 ID입니다. 설정 appBundleIdentifier 애플 제공자에서
애플 nonce 오류 애플과 Better Auth에서 보낸 nonce가 다릅니다. 한 번 생성하여 동일한 값을 재사용하세요.
앱 재시작 후 세션이 소실됩니다. 토큰은 메모리에서만 유지됩니다. persist with setData 첫 번째 요청 전에 로드합니다.

모바일 측 배포

인증 변경은 거의 네이티브가 아닙니다. 신뢰할 수 있는 원본 및 제공자는 서버 구성이며, 클라이언트 code은 TypeScript이므로 대부분의 수정은 code live updates를 통해 배포할 수 있습니다. 대신 저장소 릴리스가 아닌 Capgo live updates를 통해 배포할 수 있습니다. 새로운 바이너리가 필요할 때만 네이티브 플러그인을 추가하거나 URL 스키마를 변경할 때입니다.

Capacitor 앱에 대한 실시간 업데이트

웹-layer 버그가 활성화된 경우 Capgo을 통해 픽스를 배포하는 대신 앱 스토어 승인까지 며칠 기다리지 말고, 사용자는 배경에서 업데이트를 받으며 네이티브 변경 사항은 일반적인 검토 경로에 남겨둔다.

14일 동안 무제한 무료试用. 신용 카드가 필요하지 않습니다.

Capgo은 전문적인 모바일 앱을 만들기 위해 꼭 필요한 최고의 통찰력을 제공합니다.