본문 바로가기

Capacitor 앱에 인증 기능을 추가하는 방법 (2026)

Capacitor 앱에 인증을 추가하는 모든 방법을 비교해 보세요: 네이티브 Google/Apple 로그인, OIDC SSO, Firebase, Supabase, Neon, Better Auth, 패스키, 생체 인증.

소셜, SSO, 패스키 로그인 옵션을 제공하는 Capacitor 앱의 로그인 화면

Capacitor 앱에 인증을 추가하려면 ID 소스(자체 백엔드, Firebase, Supabase, Neon 같은 호스팅 서비스, Auth0, Okta, Entra ID 같은 OIDC 제공자, Better Auth 같은 셀프호스팅 라이브러리)를 선택하고, 제공자 로그인 페이지를 여는 작업에는 네이티브 플러그인을 사용하며, 서버에서 토큰을 검증하고, 생성된 세션을 Keychain 또는 Keystore에 저장합니다. 생체 인증과 패스키는 다음 로그인 속도를 빠르게 합니다.

이 가이드는 모든 일반적인 옵션을 올바른 Capacitor 플러그인과 플로우에 매핑합니다. 모든 앱에서 동일한 부분인 로그인 호출, 토큰 검증, 세션 저장, 생체 인증 잠금 해제에 대한 code도 포함합니다. 2026년 10월 기준 Capacitor 8에 맞게 최신화되었습니다. 각 제공자별 단계별 가이드는 아래에 링크되어 있습니다.

모든 Capacitor 앱이 결국 갖게 되는 인증 흐름

어떤 제공자를 선택하든 구조는 동일합니다:

  1. 사용자 식별 : 네이티브 소셜 시트, 시스템 브라우저의 제공자 로그인 페이지, 패스키 프롬프트, 또는 이메일과 비밀번호를 전송하는 폼.
  2. 증명 획득: ID 토큰, 인가 code, 또는 인증 서버에서 발급된 세션 토큰.
  3. 서버에서 검증: 서명, 발급자, 대상, 만료일을 확인한 후 사용자를 생성하거나 조회합니다.
  4. 세션 발급: 자체 토큰 또는 제공자 토큰을 리프레시 전략과 함께 발급합니다.
  5. 안전하게 저장 : 기기에 저장하고 API 호출에 첨부합니다.
  6. 빠른 잠금 해제 다음에는 생체 인증을 사용하고, 로그아웃 및 계정 삭제를 처리하세요.

1, 2단계는 제공업체마다 다릅니다. 3~6단계는 모든 옵션에서 직접 구현해야 하지만, SDK가 대부분을 처리해 주는 완전 호스팅형 BaaS는 예외입니다.

WebView 로그인 페이지가 제대로 작동하지 않는 이유

Capacitor 앱은 로컬 오리진을 가진 WKWebView(iOS) 또는 Android WebView에서 웹 code을 실행합니다(capacitor://localhost 또는 https://localhost). 해당 WebView 안에서 제공업체의 로그인 페이지를 로드하면 세 가지 문제가 발생합니다:

  • Google이 disallowed_useragent 페이지 표시를 거부합니다.
  • 앱이 해당 페이지가 실제 제공업체의 페이지임을 증명할 수 없기 때문이며, 이것이 RFC 8252에서 네이티브 앱에 시스템 브라우저 사용을 권장하는 이유입니다.
  • 전체 페이지 리다이렉트는 번들된 앱을 벗어나 상태를 잃게 합니다.

따라서 아래의 모든 플로우는 네이티브 SDK(Apple, Google, Facebook) 또는 시스템 브라우저 세션을 사용합니다(ASWebAuthenticationSession iOS에서는 Safari, Android에서는 Chrome Custom Tabs를 사용하여 커스텀 스킴을 통해 앱으로 돌아오는 방식입니다.

한눈에 보는 선택지

접근 방식 추천 대상 Capacitor 플러그인 백엔드 작업 가이드
Apple로 로그인 서드파티 로그인이 있는 모든 iOS 앱 @capgo/capacitor-social-login ID 토큰 검증 Apple 가이드
Google Sign-In B2C 앱, Android 우선 @capgo/capacitor-social-login ID 토큰 검증 Google 가이드
Auth0) 다양한 연결을 지원하는 호스팅 로그인 @capgo/capacitor-social-login (OAuth2) 액세스 토큰 유효성 검사 Auth0 가이드
Okta 기업용 및 B2B SSO @capgo/capacitor-social-login (OAuth2) 액세스 토큰 유효성 검사 Okta 가이드
Microsoft Entra ID Microsoft 365 조직 @capgo/capacitor-social-login (OAuth2) 액세스 토큰, Graph 검증 Entra ID 가이드
더 나은 인증 방식 셀프 호스팅, 자체 사용자 DB better-auth 클라이언트 + Social Login Better Auth 서버 실행 Better Auth 가이드
Supabase Auth 인증이 내장된 Postgres 백엔드 소셜 로그인 + supabase-js 최소 구성 Supabase 가이드
Neon Auth 관리형 Better Auth가 포함된 Neon Postgres @capgo/capacitor-neon 최소 구성 Neon 플러그인 문서
Firebase Authentication 이미 Firebase를 사용 중인 앱 @capgo/capacitor-firebase-authentication 최소 구성 Firebase 문서
패스키 자체 도메인에서 비밀번호 없는 로그인 @capgo/capacitor-passkey WebAuthn 서버 Passkey 문서
이메일 및 비밀번호 간단한 앱, 자체 백엔드 없음 (HTTP) 해싱, 재설정, 속도 제한 이 글

네이티브 소셜 로그인 (Apple, Google, Facebook)

하나의 플러그인으로 3대 소비자 제공자 및 범용 OAuth2 엔진을 지원합니다:

bun add @capgo/capacitor-social-login
bunx cap sync
import { SocialLogin } from '@capgo/capacitor-social-login';

await SocialLogin.initialize({
  apple: { clientId: 'com.example.app' },
  google: {
    webClientId: 'WEB_CLIENT_ID.apps.googleusercontent.com',
    iOSClientId: 'IOS_CLIENT_ID.apps.googleusercontent.com',
  },
});

const { result } = await SocialLogin.login({ provider: 'google', options: {} });
// send result.idToken to your server

사용하지 않는 제공자는 capacitor.config.ts (plugins.SocialLogin.providers)에서 비활성화하여 해당 SDK가 앱에 컴파일되지 않도록 하세요. Facebook을 사용하지 않는 경우 Facebook SDK의 광고 ID 권한도 제거됩니다.

각 제공자는 네이티브 설정이 필요합니다: Apple은 Xcode에서 capability와 Android용 Services ID가 필요하며, Google은 SHA-1 지문과 역방향 클라이언트 ID URL 스킴이 필요합니다. Apple 및 Google 가이드는 모든 단계와 일반적인 오류를 다룹니다.

OAuth 2.0 및 OpenID Connect 기반 엔터프라이즈 SSO

Auth0, Okta, Microsoft Entra ID, Keycloak, Cognito, OneLogin 또는 자체 OIDC 서버의 경우 플러그인의 oauth2 provider를 사용하세요. PKCE를 사용하여 code 인증 플로우를 실행합니다. ASWebAuthenticationSession iOS에서는 ASWebAuthenticationSession, Android에서는 Custom Tabs에서 실행되며, 설정 시 androidUseCustomTabs: true:

await SocialLogin.initialize({
  oauth2: {
    corp: {
      issuerUrl: 'https://sso.example.com/realms/mobile', // OIDC discovery
      clientId: 'mobile-app',
      redirectUrl: 'com.example.app://oauth/corp',
      scope: 'openid profile email offline_access',
      pkceEnabled: true,
      androidUseCustomTabs: true,
    },
  },
});

const { result } = await SocialLogin.login({
  provider: 'oauth2',
  options: { providerId: 'corp' },
});

동일한 맵에 여러 provider를 등록하고 providerId로 선택할 수 있습니다. 이는 멀티테넌트 B2B 앱에서 각 고객이 자체 IdP를 사용하도록 허용하는 방식입니다. 플러그인은 리프레시(SocialLogin.refresh), 로그아웃 기능, id_token_hint, 그리고 Ionic Auth Connect 호환 래퍼 (SocialLoginAuthConnect) Auth Connect에서 마이그레이션하는 팀을 위한 것입니다. 제공업체별 가이드: Auth0), Okta, Entra ID. 프로토콜 배경 지식은 다음을 참조하세요: Capacitor 앱에서 OAuth2를 구현하는 5단계.

호스팅 백엔드: Firebase, Supabase, Neon

데이터가 이미 Firebase, Supabase 또는 Neon에 있다면, 해당 서비스의 auth를 사용하세요. 그래야 추가 작업 없이 보안 규칙과 row-level security를 그대로 적용할 수 있습니다.

  • Supabase는: Social Login plugin으로 ID token을 가져온 뒤 호출하세요 supabase.auth.signInWithIdToken({ provider: 'google', token }). Supabase가 이를 검증하고 세션을 반환합니다. 전체 설정: Capacitor Social Login을 사용하는 Supabase.
  • Neon: Neon Auth Neon 브랜치에서 관리되는 Better Auth입니다. @capgo/capacitor-neon 이메일/비밀번호, 이메일 OTP, 또는 시스템 브라우저에서 Google, GitHub, Vercel OAuth로 네이티브 로그인 처리를 지원합니다. Neon Data API를 반환하므로, 행 수준 보안(RLS)이 적용됩니다. 전체 설정: Neon 플러그인 문서.
  • Firebase: 네이티브 Firebase Auth SDK를 래핑한 @capgo/capacitor-firebase-authentication을 사용하거나, Social Login으로 ID 토큰을 받아 JS SDK에서 Firebase 자격 증명을 생성할 수 있습니다. Firebase Google 로그인 문서.

셀프 호스팅: Better Auth

Better Auth는 사용자 데이터를 자체 데이터베이스에 저장하는 오픈소스 TypeScript 인증 라이브러리입니다. WKWebView에서 크로스사이트 쿠키가 불안정하기 때문에, 앱 오리진을 신뢰하고 베어러 토큰으로 전환하면 Capacitor에서 정상적으로 동작합니다. 소셜 로그인은 네이티브 플러그인과 ID 토큰 핸드오프를 통해 처리됩니다. 단계별 가이드: Capacitor 앱에서 Better Auth 사용법.

패스키

패스키는 iCloud 키체인 또는 Google 비밀번호 관리자에 저장된 키 페어로 비밀번호를 대체합니다. 앱이 웹사이트 도메인과 연관되어 있어야 합니다(apple-app-site-association iOS의 경우, assetlinks.json Android)와 WebAuthn 서버입니다.

@capgo/capacitor-passkey 표준 WebAuthn code을 유지할 수 있습니다. relying party는 다음에서 구성하세요: capacitor.config.ts, 시작 시 shim을 한 번 호출하고 navigator.credentials.create() 및 .get() 네이티브 패스키 API로 라우팅됩니다:

import { CapacitorPasskey } from '@capgo/capacitor-passkey';

await CapacitorPasskey.autoShimWebAuthn();

// existing WebAuthn code keeps working
const assertion = await navigator.credentials.get({
  publicKey: requestOptionsFromServer,
});

Better Auth 같은 라이브러리나 Auth0, Okta 같은 호스팅 제공업체를 WebAuthn 서버로 사용할 수 있습니다. 자세한 내용은 passkey plugin 페이지를.

자체 백엔드로 이메일·비밀번호 인증

플러그인은 필요 없으며, 그저 fetch입니다. 작업은 서버에서 이루어집니다. Argon2id 또는 bcrypt로 해싱하고, 로그인 시도에 rate limit을 걸고, 인증 및 재설정 이메일을 보내고, 계정 삭제를 지원해야 합니다. 재설정 및 인증 링크는 Universal Links와 App Links로 앱에서 열리게 해서, 휴대폰에서 링크가 올바른 곳으로 연결되도록 하세요. 이 모든 걸 직접 관리할 이유가 없다면, Better Auth 같은 라이브러리나 호스팅 서비스를 쓰는 게 같은 기능을 더 적은 리스크로 제공받는 방법입니다.

항상 서버에서 토큰을 검증하세요

클라이언트 측 검증은 우회될 수 있습니다. 어떤 제공업체를 쓰든, 서버는 세션을 만들기 전에 반드시 토큰을 검증해야 합니다:

import { createRemoteJWKSet, jwtVerify } from 'jose';

type IssuerConfig = {
  jwks: ReturnType<typeof createRemoteJWKSet>;
  issuer: string | string[];
  audience: string[];
};

const issuers: Record<'google' | 'apple', IssuerConfig> = {
  google: {
    jwks: createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs')),
    issuer: ['https://accounts.google.com', 'accounts.google.com'],
    audience: ['WEB_CLIENT_ID.apps.googleusercontent.com', 'IOS_CLIENT_ID.apps.googleusercontent.com'],
  },
  apple: {
    jwks: createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys')),
    issuer: 'https://appleid.apple.com',
    audience: ['com.example.app', 'com.example.app.signin'],
  },
};

export async function verifyIdToken(provider: 'google' | 'apple', idToken: string) {
  const cfg = issuers[provider];
  const { payload } = await jwtVerify(idToken, cfg.jwks, {
    issuer: cfg.issuer,
    audience: cfg.audience,
  });
  return payload; // use payload.sub as the stable provider user ID
}

제공업체의 sub (제공업체 이름 포함)를 기준으로 하고, 이메일이 아닙니다. 제공업체가 이메일을 verified로 표시한 경우에만(email_verified: true) 이메일로 계정을 연결하세요. Meta의 Limited Login 토큰에는 이 claim이 없습니다.

세션을 안전하게 저장하세요

localStorage 및 Capacitor Preferences는 평문 파일입니다. 수명이 긴 토큰은 Keychain(iOS) 또는 Keystore로 암호화된 저장소(Android)에 보관하세요. @capgo/capacitor-native-biometric 간단한 setData, getData 및 deleteData 방법이 있습니다:

bun add @capgo/capacitor-native-biometric
bunx cap sync
import { NativeBiometric } from '@capgo/capacitor-native-biometric';

export const sessionStore = {
  async save(token: string) {
    await NativeBiometric.setData({ key: 'session.token', value: token });
  },
  async load(): Promise<string | null> {
    try {
      const { value } = await NativeBiometric.getData({ key: 'session.token' });
      return value;
    } catch {
      return null;
    }
  },
  async clear() {
    await NativeBiometric.deleteData({ key: 'session.token' }).catch(() => {});
  },
};

액세스 토큰은 수명을 짧게 유지하고, 리프레시 토큰 또는 서버 세션으로 갱신하세요. 저희 안전한 토큰 저장 가이드에서는 토큰 로테이션과 폐기에 대해 더 자세히 다룹니다.

생체 인증: 신원이 아닌 잠금 해제

Face ID와 지문은 휴대폰을 든 사람이 잠금을 해제할 수 있다는 것만 증명합니다. 저장된 세션에 대한 접근을 제어하는 데 사용하세요:

import { AccessControl, NativeBiometric } from '@capgo/capacitor-native-biometric';

// after a real login, offer biometric unlock
await NativeBiometric.setData({
  key: 'session.refresh',
  value: refreshToken,
  accessControl: AccessControl.BIOMETRY_ANY,
});

// next app start
const { value } = await NativeBiometric.getSecureData({
  key: 'session.refresh',
  reason: 'Unlock your account',
});
// exchange `value` with your server for a fresh access token

사용하면 accessControl 설정하면 생체 인증이 성공한 후에만 OS가 값을 반환하므로, 보호는 JavaScript가 아니라 Keychain이나 Keystore에서 강제됩니다. 서버 측 세션 만료와 함께 사용하고, 고위험 앱이라면 루팅/탈옥 탐지도 병행하세요. 자세한 내용은 Capacitor 앱의 생체 인증 문서에서 확인하세요.

인증 방식 선택하기

이런 경우… 사용
iOS 및 Android 소비자 앱 출시 Social Login으로 Apple + Google, 이메일 또는 패스키
Microsoft 365를 사용하는 기업에 판매 OAuth2 프로바이더를 통한 Entra ID
고객사마다 다양한 엔터프라이즈 IdP 필요 Auth0 또는 Okta를 브로커로 사용하거나, 여러 OAuth2 프로바이더를 통해 providerId
이미 Supabase 또는 Firebase 사용 중 Native ID token sign-in으로 기존 인증 사용
이미 Neon 사용 중 Neon Auth를 통해 @capgo/capacitor-neon
벤더 없이 자체 사용자 테이블을 원하시나요? 더 나은 인증 방식
비밀번호 없이 쓰고 싶다면 Passkeys, 이메일 매직 링크 같은 폴백과 함께
빠른 재로그인이 필요할 때 위 항목 중 하나에 저장된 세션의 생체 인증 잠금 해제

로그인에 영향을 주는 App Store 및 Play 스토어 규정

  • Apple 4.8 로그인 서비스: 제3자 로그인을 주요 계정 시스템으로 쓸 경우, 그에 상응하는 프라이버시 중심 옵션이 필요합니다. Sign in with Apple이 이를 충족합니다.
  • Apple 5.1.1(v): 계정 생성 시 앱 내 계정 삭제가 필요하며, Sign in with Apple 토큰은 폐기해야 합니다. 참고: 계정 삭제 준수.
  • Google Play 계정 삭제: 계정이 있는 앱은 앱 내에서와 Play Console에 등록된 웹 링크를 통해 삭제를 제공해야 합니다.
  • 리뷰어 액세스: 리뷰어에게 동작하는 데모 계정을 제공하세요. 로그인이 SSO 전용이라면 테스트 테넌트 사용자를 제공하세요.
  • Xcode 26: App Store Connect는 2026년 4월부터 Xcode 26과 iOS 26 SDK로 빌드한 앱을 요구하므로, 새 인증 기능을 추가한 릴리스를 제출하기 전에 업데이트하세요.

인증 변경 사항을 안전하게 배포하기

인증 버그는 모든 사용자를 막으므로 빠르게 수정해야 합니다. 네이티브 변경 사항(엔티틀먼트, URL 스킴, 인텐트 필터)은 스토어 빌드가 필요합니다. 프로바이더 설정, 스코프, 에러 처리, UI 등 TypeScript로 작성된 모든 코드는 Live Update로 배포할 수 있습니다. Capgo Live Update 사용하기 문제가 생기면 롤백할 수 있습니다. Capgo 빌드 새 Native 릴리스가 정말 필요할 때 클라우드에서 서명된 iOS 및 Android 바이너리를 생성합니다.

다음 단계

사용할 프로바이더를 선택하고 해당 가이드를 따라가세요:

Capacitor 앱용 Live updates

웹 레이어 버그가 라이브 상태라면, 앱 스토어 승인을 며칠씩 기다리지 말고 Capgo를 통해 수정 사항을 배포하세요. 네이티브 변경 사항은 정상 리뷰 절차를 그대로 따르는 반면, 사용자는 백그라운드에서 업데이트를 받습니다.

블로그 최신 글

Capgo는 정말 프로페셔널한 모바일 앱을 만드는 데 필요한 최고의 인사이트를 제공합니다.