{"_id":"@dongminyu/react-native-naver-login","_rev":"10-9b2c8f7b7bb79a9f009152257082f1d3","name":"@dongminyu/react-native-naver-login","dist-tags":{"latest":"0.1.4"},"versions":{"0.1.4":{"name":"@dongminyu/react-native-naver-login","version":"0.1.4","keywords":["react-native","ios","android","naver","naver-login","네이버","네아로","oauth","authentication","login","turbo-module","new-architecture","fabric"],"author":{"url":"https://github.com/AndrewDongminYoo","name":"Dongmin, Yu","email":"ydm2790@gmail.com"},"license":"MIT","_id":"@dongminyu/react-native-naver-login@0.1.4","maintainers":[{"name":"andrewdongminyoo","email":"ydm2790@gmail.com"}],"homepage":"https://github.com/AndrewDongminYoo/react-native-naver-login#readme","bugs":{"url":"https://github.com/AndrewDongminYoo/react-native-naver-login/issues"},"dist":{"shasum":"9783bc7a571611e13043d3400f8b3f1a7288b2a4","tarball":"https://registry.npmjs.org/@dongminyu/react-native-naver-login/-/react-native-naver-login-0.1.4.tgz","fileCount":33,"integrity":"sha512-htUggux8IB1WLDYL1Yzpxe52a+d9cP6RZBeQL1a4vroTGwBCzsd2Gxl2s9aACpy0j5LQBS+lbjoRLc6cPnqGdA==","signatures":[{"sig":"MEYCIQCtN6xuB3Zpw4azXReRlQd5TlK28s+WRImgrye2Hg4fEgIhAKao5alv5kT+7GkLHvFbONwhTfYJdlmkO8/sXp+DpNde","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75455},"main":"./lib/module/index.js","types":"./lib/typescript/src/index.d.ts","exports":{".":{"types":"./lib/typescript/src/index.d.ts","source":"./src/index.tsx","default":"./lib/module/index.js"},"./package.json":"./package.json"},"gitHead":"e5399514df855dbe298c70f816c350fee31e7cfb","scripts":{"web":"vite","lint":"eslint \"**/*.{js,ts,tsx}\"","test":"jest","clean":"del-cli android/build example/android/build example/android/app/build example/ios/build lib","example":"yarn workspace react-native-naver-login-example","prepare":"bob build","build:web":"vite build","typecheck":"tsc --noEmit","watchman-reset":"watchman watch-del $PWD && watchman watch-project $PWD"},"_npmUser":{"name":"andrewdongminyoo","email":"ydm2790@gmail.com"},"repository":{"url":"git+https://github.com/AndrewDongminYoo/react-native-naver-login.git","type":"git"},"workspaces":["example"],"_npmVersion":"11.16.0","description":"React Native TurboModule for Naver OAuth (네이버 아이디로 로그인) on iOS and Android, targeting the New Architecture.","directories":{},"_nodeVersion":"24.18.0","codegenConfig":{"name":"NaverLoginSpec","type":"modules","android":{"javaPackageName":"com.naverlogin"},"jsSrcsDir":"src"},"publishConfig":{"registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"packageManager":"yarn@4.11.0","devDependencies":{"jest":"^30.3.0","react":"19.2.3","turbo":"^2.9.8","eslint":"^9.39.4","del-cli":"^7.0.0","prettier":"^3.8.3","@eslint/js":"^9.39.4","typescript":"^6.0.3","@types/react":"^19.2.0","react-native":"0.85.2","@jest/globals":"^30.0.0","@eslint/compat":"^2.0.3","@eslint/eslintrc":"^3.3.5","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","react-native-builder-bob":"^0.41.0","@react-native/jest-preset":"0.85.2","@react-native/babel-preset":"0.85.2","@react-native/eslint-config":"0.85.2"},"peerDependencies":{"react":"*","react-native":"*"},"_npmOperationalInternal":{"tmp":"tmp/react-native-naver-login_0.1.4_1782958090596_0.7007436053286664","host":"s3://npm-registry-packages-npm-production"},"create-react-native-library":{"type":"turbo-module","tools":["eslint","jest","vite"],"version":"0.62.0","languages":"kotlin-objc"},"deprecated":"Renamed to react-native-naver-login-turbo"}},"time":{"created":"2026-07-02T02:08:10.246Z","modified":"2026-07-12T09:14:22.776Z","0.1.0":"2026-05-07T10:32:33.124Z","0.1.2":"2026-05-12T05:01:19.316Z","0.1.3":"2026-05-14T01:16:33.762Z","0.1.4":"2026-07-02T02:08:10.783Z"},"bugs":{"url":"https://github.com/AndrewDongminYoo/react-native-naver-login/issues"},"author":{"url":"https://github.com/AndrewDongminYoo","name":"Dongmin, Yu","email":"ydm2790@gmail.com"},"license":"MIT","homepage":"https://github.com/AndrewDongminYoo/react-native-naver-login#readme","keywords":["react-native","ios","android","naver","naver-login","네이버","네아로","oauth","authentication","login","turbo-module","new-architecture","fabric"],"repository":{"url":"git+https://github.com/AndrewDongminYoo/react-native-naver-login.git","type":"git"},"description":"React Native TurboModule for Naver OAuth (네이버 아이디로 로그인) on iOS and Android, targeting the New Architecture.","maintainers":[{"name":"andrewdongminyoo","email":"ydm2790@gmail.com"}],"readme":"# @dongminyu/react-native-naver-login\n\n[![npm version](https://img.shields.io/npm/v/@dongminyu/react-native-naver-login)](https://www.npmjs.com/package/@dongminyu/react-native-naver-login)\n[![license](https://img.shields.io/npm/l/@dongminyu/react-native-naver-login)](./LICENSE)\n[![platform - ios](https://img.shields.io/badge/platform-iOS%2015.1%2B-blue?logo=apple)](https://developer.apple.com)\n[![platform - android](https://img.shields.io/badge/platform-Android%2024%2B-green?logo=android)](https://developer.android.com)\n[![new architecture](https://img.shields.io/badge/New%20Architecture-TurboModule-orange)](https://reactnative.dev/docs/the-new-architecture/landing-page)\n\n**React Native New Architecture (TurboModule)** library for Naver OAuth 2.0 login on iOS and Android.\n\nDesigned to be API-compatible with [`@react-native-seoul/naver-login`](https://github.com/crossplatformkorea/react-native-naver-login), so it can serve as a drop-in replacement in existing projects.\n\n> **New Architecture only.** This library does not support the legacy Bridge (Old Architecture).\n\n**[한국어 문서 (Korean README)](./README.ko.md)**\n\n---\n\n## Table of Contents\n\n- [Requirements](#requirements)\n- [Naver Developer Console Setup](#naver-developer-console-setup)\n- [Installation](#installation)\n- [iOS Setup](#ios-setup)\n- [Android Setup](#android-setup)\n- [Usage](#usage)\n- [API Reference](#api-reference)\n- [Behavior Notes](#behavior-notes)\n- [Running the Example App](#running-the-example-app)\n- [Migrating from @react-native-seoul/naver-login](#migrating-from-react-native-seoulnaver-login)\n- [Troubleshooting](#troubleshooting)\n- [License](#license)\n\n---\n\n## Requirements\n\n| Item                  | Minimum version                   |\n| --------------------- | --------------------------------- |\n| React Native          | 0.76+ (New Architecture required) |\n| iOS                   | 15.1+                             |\n| Android               | API 24 (Android 7.0)+             |\n| Xcode                 | 15+                               |\n| Android Gradle Plugin | 8.x+                              |\n\n---\n\n## Naver Developer Console Setup\n\nBefore using this library, register your application at the [Naver Developer Console](https://developers.naver.com/apps/#/register).\n\n1. **Register an application** → Select **Naver Login** as the API to use.\n2. Configure the login service environment:\n   - **iOS**: Enter your iOS Bundle ID (e.g., `com.example.myapp`)\n   - **Android**: Enter your Android package name (e.g., `com.example.myapp`)\n3. After registration, note your **Client ID** (`consumerKey`) and **Client Secret** (`consumerSecret`).\n4. For iOS, decide on a **URL Scheme** for the OAuth callback (e.g., `naverlogin.myapp`).\n\n---\n\n## Installation\n\n```sh\nnpm install @dongminyu/react-native-naver-login\n# or\nyarn add @dongminyu/react-native-naver-login\n```\n\n### iOS\n\n```sh\ncd ios && pod install\n```\n\nThe podspec automatically pulls in `naveridlogin-sdk-ios` via CocoaPods. No manual SDK download or framework setup is needed.\n\n### Android\n\n`com.navercorp.nid:oauth:5.10.0` is automatically added from Maven Central via `android/build.gradle`. No additional steps required.\n\n---\n\n## iOS Setup\n\n### Info.plist — Register URL Scheme\n\nRegister a URL Scheme so your app can receive the OAuth callback from the Naver app.\n\n```xml\n<key>CFBundleURLTypes</key>\n<array>\n  <dict>\n    <key>CFBundleURLSchemes</key>\n    <array>\n      <string>YOUR_URL_SCHEME</string>\n    </array>\n  </dict>\n</array>\n```\n\n### Info.plist — Naver App Allowlist\n\nAllow the system to query whether the Naver app is installed.\n\n```xml\n<key>LSApplicationQueriesSchemes</key>\n<array>\n  <string>naversearchapp</string>\n  <string>naversearchthirdlogin</string>\n</array>\n```\n\n### No AppDelegate Changes Needed\n\nThis library subscribes to `RCTOpenURLNotification` internally to handle the OAuth callback URL. **You do not need to add an `openURL:` handler to your `AppDelegate`.**\n\n---\n\n## Android Setup\n\n### AndroidManifest.xml\n\nRegister the Naver login activity.\n\n```xml\n<application ...>\n  <activity\n    android:name=\"com.navercorp.nid.oauth.OAuthLoginActivity\"\n    android:theme=\"@android:style/Theme.Translucent.NoTitleBar\" />\n</application>\n```\n\n### ProGuard\n\nIf you use ProGuard, add the following rule.\n\n```plaintext\n-keep class com.navercorp.nid.** { *; }\n```\n\n---\n\n## Usage\n\n### Initialize\n\nCall this once at app startup, typically inside `useEffect` in your root component.\n\n```typescript\nimport NaverLogin from '@dongminyu/react-native-naver-login';\n\nNaverLogin.initialize({\n  consumerKey: 'YOUR_CLIENT_ID',\n  consumerSecret: 'YOUR_CLIENT_SECRET',\n  appName: 'MyApp',\n  serviceUrlSchemeIOS: 'YOUR_URL_SCHEME', // iOS only\n  disableNaverAppAuthIOS: false, // iOS only, default false\n});\n```\n\n### Login\n\n```typescript\nconst result = await NaverLogin.login();\n\nif (result.isSuccess && result.successResponse) {\n  const { accessToken, refreshToken, tokenType, expiresAtUnixSecondString } =\n    result.successResponse;\n  console.log('Login succeeded:', accessToken);\n} else if (result.failureResponse?.isCancel) {\n  console.log('User cancelled login.');\n} else {\n  console.log('Login failed:', result.failureResponse?.message);\n}\n```\n\n> **Important:** `login()` never rejects. Both errors and cancellations resolve as `{ isSuccess: false, failureResponse: { ... } }`. Check `result.isSuccess` — do not use `try/catch` to detect failure.\n\n### Get Profile\n\n```typescript\nconst profile = await NaverLogin.getProfile(accessToken);\n\nconst {\n  id,\n  name,\n  email,\n  nickname,\n  profile_image,\n  birthday,\n  birthyear,\n  mobile,\n  gender,\n} = profile.response;\n```\n\n### Logout (local token removal only)\n\nRemoves the locally stored token without revoking it on the server.\n\n```typescript\nawait NaverLogin.logout();\n```\n\n### Unlink (server revocation + local removal)\n\nSends a revocation request to the Naver server and then removes the local token. This fully severs the connection between your app and the user's Naver account.\n\n```typescript\ntry {\n  await NaverLogin.deleteToken();\n} catch (e) {\n  console.error('Unlink failed:', e);\n}\n```\n\n### Full Example\n\n```typescript\nimport { useEffect, useState } from 'react';\nimport { Button, Text, View } from 'react-native';\nimport NaverLogin, {\n  type NaverLoginSuccessResponse,\n} from '@dongminyu/react-native-naver-login';\n\nexport default function LoginScreen() {\n  const [token, setToken] = useState<NaverLoginSuccessResponse | null>(null);\n\n  useEffect(() => {\n    NaverLogin.initialize({\n      consumerKey: 'YOUR_CLIENT_ID',\n      consumerSecret: 'YOUR_CLIENT_SECRET',\n      appName: 'MyApp',\n      serviceUrlSchemeIOS: 'YOUR_URL_SCHEME',\n    });\n  }, []);\n\n  const handleLogin = async () => {\n    const result = await NaverLogin.login();\n    if (result.isSuccess && result.successResponse) {\n      setToken(result.successResponse);\n    }\n  };\n\n  const handleLogout = async () => {\n    await NaverLogin.logout();\n    setToken(null);\n  };\n\n  return (\n    <View>\n      {token ? (\n        <>\n          <Text>{token.accessToken}</Text>\n          <Button title=\"Logout\" onPress={handleLogout} />\n        </>\n      ) : (\n        <Button title=\"Login with Naver\" onPress={handleLogin} />\n      )}\n    </View>\n  );\n}\n```\n\n---\n\n## API Reference\n\n### `NaverLogin.initialize(params)`\n\n| Parameter                | Type      | Required     | Description                                       |\n| ------------------------ | --------- | ------------ | ------------------------------------------------- |\n| `consumerKey`            | `string`  | ✓            | Client ID from Naver Developer Console            |\n| `consumerSecret`         | `string`  | ✓            | Client Secret from Naver Developer Console        |\n| `appName`                | `string`  | ✓            | App name displayed on the login screen            |\n| `serviceUrlSchemeIOS`    | `string`  | iOS required | URL Scheme for the iOS OAuth callback             |\n| `disableNaverAppAuthIOS` | `boolean` | —            | Disable native Naver app login (default: `false`) |\n\nReturns: `void` (synchronous)\n\n---\n\n### `NaverLogin.login()`\n\nReturns: `Promise<NaverLoginResponse>` — **never rejects.**\n\n```typescript\ntype NaverLoginResponse = {\n  isSuccess: boolean;\n  successResponse?: NaverLoginSuccessResponse;\n  failureResponse?: NaverLoginFailureResponse;\n};\n\ntype NaverLoginSuccessResponse = {\n  accessToken: string;\n  refreshToken: string;\n  expiresAtUnixSecondString: string; // Unix timestamp in seconds, as a string\n  tokenType: string; // typically \"Bearer\"\n};\n\ntype NaverLoginFailureResponse = {\n  message: string;\n  isCancel: boolean;\n  lastErrorCodeFromNaverSDK?: string; // Android only\n  lastErrorDescriptionFromNaverSDK?: string; // Android only\n};\n```\n\n---\n\n### `NaverLogin.logout()`\n\nReturns: `Promise<void>` — can reject if the native layer throws.\n\nRemoves the locally cached token. The token remains valid on the server.\n\n---\n\n### `NaverLogin.deleteToken()`\n\nReturns: `Promise<void>` — rejects if the server request fails.\n\nSends a revocation request to Naver's server, then removes the local token. Unlike `logout()`, this can reject on network failure.\n\n---\n\n### `NaverLogin.getProfile(accessToken)`\n\n| Parameter     | Type     | Description                       |\n| ------------- | -------- | --------------------------------- |\n| `accessToken` | `string` | Access token obtained after login |\n\nReturns: `Promise<GetProfileResponse>` — rejects on HTTP or network errors.\n\n```typescript\ntype GetProfileResponse = {\n  resultcode: string; // \"00\" = success\n  message: string; // \"success\"\n  response: NaverProfileData;\n};\n\ntype NaverProfileData = {\n  id: string;\n  email: string;\n  name: string;\n  profile_image: string | null;\n  nickname: string | null;\n  birthday: string | null; // \"MM-DD\" format\n  birthyear: number | null;\n  age: string | null; // e.g. \"20-29\"\n  gender: string | null; // \"M\" | \"F\" | \"U\"\n  mobile: string | null;\n  mobile_e164: string | null;\n  ci?: string | null; // CI (Connecting Information); only present if the Naver app has business-info + CI scope\n};\n```\n\n---\n\n## Behavior Notes\n\n### `login()` never rejects\n\nAll failure cases — errors, cancellations, network issues — resolve as `{ isSuccess: false, failureResponse: {...} }`. A `try/catch` block will never catch a login failure.\n\n```typescript\n// ✅ Correct\nconst result = await NaverLogin.login();\nif (!result.isSuccess) {\n  const { isCancel, message } = result.failureResponse!;\n}\n\n// ❌ Wrong — catch is never called\ntry {\n  const result = await NaverLogin.login();\n} catch (e) {\n  // unreachable\n}\n```\n\n### Concurrent login protection\n\nOn both iOS and Android, if a second `login()` call arrives while one is already in progress, it immediately resolves as `{ isSuccess: false }`. Wait for the current login to finish before issuing a new one.\n\n### `logout` vs `deleteToken`\n\n|                      | `logout()`      | `deleteToken()`     |\n| -------------------- | --------------- | ------------------- |\n| Removes local token  | ✓               | ✓                   |\n| Revokes server token | ✗               | ✓                   |\n| Requires network     | ✗               | ✓                   |\n| Can reject           | ✓               | ✓                   |\n| Use case             | Simple sign-out | Full account unlink |\n\n### No AppDelegate changes needed (iOS)\n\nWhen `initialize()` is called, the library subscribes to `RCTOpenURLNotification` to automatically process the return URL from the Naver app. **If you previously added an `openURL:` handler in your AppDelegate for Naver, remove it** to avoid conflicts.\n\n### Naver app not installed (iOS)\n\nWhen `disableNaverAppAuthIOS` is `false` (default), the library attempts native app login if the Naver app is installed. If it is not installed, it automatically falls back to an in-app WebView login.\n\n### Parsing `expiresAtUnixSecondString`\n\n```typescript\nconst expiresAt = new Date(parseInt(expiresAtUnixSecondString, 10) * 1000);\n```\n\n---\n\n## Running the Example App\n\nThe `example/` directory contains a working sample app. Complete the checklist below before running it.\n\n### Checklist\n\n#### Step 1: Register your app at the Naver Developer Console\n\nRegister an application at [developers.naver.com](https://developers.naver.com/apps/#/register).\n\n| Field                             | Value                                                                       |\n| --------------------------------- | --------------------------------------------------------------------------- |\n| API                               | Naver Login                                                                 |\n| iOS Bundle ID                     | Bundle ID from Xcode (e.g., `org.reactjs.native.example.NaverLoginExample`) |\n| Android package name              | `com.naverloginexample`                                                     |\n| Android app signature (`keyhash`) | Debug keystore hash extracted via `adb shell` or `keytool`                  |\n\nAfter registration you will receive a **Client ID** and **Client Secret**.\n\n#### Step 2: Set credentials in `example/src/App.tsx`\n\nReplace the three constants at the top of the file with your actual values.\n\n```typescript\n// example/src/App.tsx\nconst CLIENT_ID = 'YOUR_CLIENT_ID'; // ← your Client ID\nconst CLIENT_SECRET = 'YOUR_CLIENT_SECRET'; // ← your Client Secret\nconst URL_SCHEME = 'naverloginexample'; // ← already configured, no change needed\n```\n\n#### Step 3: iOS `Info.plist` (already configured)\n\n`example/ios/NaverLoginExample/Info.plist` already includes the following.\n\n```xml\n<!-- URL Scheme: receives the OAuth callback from the Naver app -->\n<key>CFBundleURLTypes</key>\n<array>\n  <dict>\n    <key>CFBundleURLSchemes</key>\n    <array>\n      <string>naverloginexample</string>\n    </array>\n  </dict>\n</array>\n\n<!-- Allows querying whether the Naver app is installed -->\n<key>LSApplicationQueriesSchemes</key>\n<array>\n  <string>naversearchapp</string>\n  <string>naversearchthirdlogin</string>\n</array>\n```\n\n> **A missing `CFBundleURLSchemes` entry is the most common mistake.** Without it, the app never receives the OAuth callback, resulting in `Failed to open URL naverloginexample://thirdPartyLoginResult`.\n\n#### Step 4: Android `AndroidManifest.xml` (already configured)\n\n`example/android/app/src/main/AndroidManifest.xml` already includes the following activity.\n\n```xml\n<activity\n  android:name=\"com.navercorp.nid.oauth.OAuthLoginActivity\"\n  android:theme=\"@android:style/Theme.Translucent.NoTitleBar\" />\n```\n\n#### Step 5: Run the example app\n\n```sh\n# Install dependencies (first time only)\nyarn\ncd example/ios && pod install && cd ../..\n\n# Start Metro bundler (separate terminal)\nyarn example start\n\n# Run on a platform\nyarn example ios     # iOS Simulator\nyarn example android # Android Emulator or physical device\n```\n\n### Physical device testing — iOS\n\nThe iOS Simulator does not have the Naver app, so login falls back to WebView. To test native Naver app login on a real device, ensure you have a valid **Team** and **Provisioning Profile** set in Xcode.\n\n### Physical device testing — Android\n\nExtract the **app signature hash** to register with the Naver Developer Console.\n\n```sh\n# Extract debug keystore hash (for development)\nkeytool -exportcert -keystore ~/.android/debug.keystore \\\n  -alias androiddebugkey -storepass android | \\\n  openssl sha1 -binary | openssl base64\n```\n\nPaste the output into the Android app registration field labeled \"SHA-1 fingerprint of the app signing certificate\" in the Naver Developer Console.\n\n---\n\n## Migrating from @react-native-seoul/naver-login\n\n### What changed\n\n| Item                  | Before (`@react-native-seoul`) | This library                       |\n| --------------------- | ------------------------------ | ---------------------------------- |\n| Architecture          | Old Bridge                     | New Architecture (TurboModule)     |\n| `getAgreement`        | Supported                      | **Removed** (Naver API deprecated) |\n| AppDelegate setup     | Required                       | **Not required**                   |\n| iOS `openURL` handler | Added in AppDelegate           | Handled internally by the library  |\n\n### What stayed the same\n\n- `initialize()`, `login()`, `logout()`, `deleteToken()`, `getProfile()` signatures are identical\n- `NaverLoginResponse`, `NaverLoginSuccessResponse`, `NaverLoginFailureResponse`, `GetProfileResponse`, `NaverProfileData` types are identical\n- The `login()` never-rejects contract is preserved\n\n---\n\n## Troubleshooting\n\n### iOS build error: `naveridlogin-sdk-ios` not found\n\n```sh\ncd ios && pod install --repo-update\n```\n\n### iOS: app does not return after login\n\n1. Verify that the URL Scheme in `Info.plist` matches the `serviceUrlSchemeIOS` value passed to `initialize()`.\n2. Verify that the iOS Bundle ID registered in the Naver Developer Console matches your actual Bundle ID.\n3. Verify that `LSApplicationQueriesSchemes` contains both `naversearchapp` and `naversearchthirdlogin`.\n\n### Android build error: Manifest merger conflict\n\nCheck whether `OAuthLoginActivity` is declared twice in `AndroidManifest.xml`. The library declares it internally, so you should not add it manually.\n\n### Android: `login()` immediately returns `isSuccess: false`\n\nThis happens when `login()` is called while the app is in the background (no current Activity). Only call `login()` in response to a user interaction.\n\n### `deleteToken()` rejects\n\nThe request failed due to a network error or the token was already expired. If you want to sign the user out locally regardless of server-side revocation, use `logout()` instead.\n\n---\n\n## License\n\nMIT © [Dongmin Yu](https://github.com/AndrewDongminYoo)\n","readmeFilename":"README.md"}