npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-nitro-auth

v0.6.1

Published

High-performance authentication library for React Native with Google Sign-In, Apple Sign-In, and Microsoft Sign-In support, powered by Nitro Modules (JSI)

Readme

react-native-nitro-auth

npm license react-native nitro-modules

Fast React Native authentication for Google Sign-In, Apple Sign-In, and Microsoft Entra ID, built on Nitro Modules and JSI.

react-native-nitro-auth gives Expo and React Native apps one typed API for native social login, web OAuth, token refresh, incremental scopes, and auth state listeners without owning your app's long-term token storage.

Why Use It?

  • One package for Google, Apple, and Microsoft authentication on React Native.
  • Native iOS and Android bridges powered by react-native-nitro-modules.
  • Expo config plugin for client IDs, URL schemes, entitlements, and Android resources.
  • Web implementation for Expo web with Google, Apple, and Microsoft OAuth.
  • Typed useAuth() hook, AuthService, SocialButton, and AuthError.
  • App-owned persistence model: tokens stay in memory unless your app stores a snapshot.
  • Built-in flows for silent restore, token refresh, account picker, login hints, and incremental Google scopes.
  • Consistent AuthError mapping for async AuthService failures on native and web.

Choose Your Path

| Need | Use | | ---------------------------------------------------------------------- | ----------------------------------------------------------------- | | Google, Apple, or Microsoft sign-in in an Expo or React Native app | react-native-nitro-auth | | Generic OAuth or OIDC provider not covered by this package | expo-auth-session or react-native-app-auth | | Firebase user management, password auth, MFA, and hosted auth platform | @react-native-firebase/auth, Auth0, Authgear, or your IDaaS SDK | | Server-side session validation | Your backend; client JWT decode is display-only |

Install

bun add react-native-nitro-auth react-native-nitro-modules

For Expo projects, prebuild after adding the config plugin:

bunx expo prebuild --clean

The example app uses Expo Continuous Native Generation. Its apps/example/android and apps/example/ios folders are generated local artifacts and intentionally ignored by git.

For bare React Native projects, install pods after installing the package:

cd ios && pod install

Requirements

| Runtime | Requirement | | ------------------ | ---------------------------------------- | | React Native | >=0.75 peer range | | Nitro Modules | >=0.35 peer range | | iOS | 16.4+ for Expo SDK 56 | | Android | min SDK 24+ recommended | | Validated baseline | Expo SDK 56, React Native 0.85, React 19 |

The package keeps a wide React Native peer range for existing consumers, but this release is validated against Expo SDK 56, React Native 0.85.3, React 19.2.3, and Nitro Modules 0.35.7.

Expo Setup

Add the plugin to app.json or app.config.js.

export default {
  expo: {
    scheme: "myapp",
    ios: {
      bundleIdentifier: "com.company.myapp",
    },
    android: {
      package: "com.company.myapp",
    },
    plugins: [
      [
        "react-native-nitro-auth",
        {
          ios: {
            googleClientId: process.env.GOOGLE_IOS_CLIENT_ID,
            googleServerClientId: process.env.GOOGLE_SERVER_CLIENT_ID,
            googleUrlScheme: process.env.GOOGLE_IOS_URL_SCHEME,
            appleSignIn: true,
            microsoftClientId: process.env.MICROSOFT_CLIENT_ID,
            microsoftTenant: process.env.MICROSOFT_TENANT,
            microsoftB2cDomain: process.env.MICROSOFT_B2C_DOMAIN,
          },
          android: {
            googleClientId: process.env.GOOGLE_WEB_CLIENT_ID,
            microsoftClientId: process.env.MICROSOFT_CLIENT_ID,
            microsoftTenant: process.env.MICROSOFT_TENANT,
            microsoftB2cDomain: process.env.MICROSOFT_B2C_DOMAIN,
          },
        },
      ],
    ],
    extra: {
      googleWebClientId: process.env.GOOGLE_WEB_CLIENT_ID,
      appleWebClientId: process.env.APPLE_WEB_CLIENT_ID,
      microsoftClientId: process.env.MICROSOFT_CLIENT_ID,
      microsoftTenant: process.env.MICROSOFT_TENANT,
      microsoftB2cDomain: process.env.MICROSOFT_B2C_DOMAIN,
      nitroAuthWebStorage: "memory",
      nitroAuthPersistTokensOnWeb: false,
    },
  },
};

Plugin Options

| Option | Platform | Purpose | | ---------------------------- | -------- | ---------------------------------------------------------------------- | | ios.googleClientId | iOS | Google iOS OAuth client ID | | ios.googleServerClientId | iOS | Google web/server client ID for server auth code flows | | ios.googleUrlScheme | iOS | Reversed iOS client ID URL scheme | | ios.appleSignIn | iOS | Adds Apple Sign-In entitlement when true | | ios.microsoftClientId | iOS | Microsoft app/client ID | | ios.microsoftTenant | iOS | Microsoft tenant, common, organizations, consumers, or tenant ID | | ios.microsoftB2cDomain | iOS | Azure AD B2C domain | | android.googleClientId | Android | Google web OAuth client ID | | android.microsoftClientId | Android | Microsoft app/client ID | | android.microsoftTenant | Android | Microsoft tenant | | android.microsoftB2cDomain | Android | Azure AD B2C domain |

Provider Setup

Google Sign-In

Create OAuth clients in Google Cloud Console:

  • iOS client ID for your bundle identifier.
  • Web client ID for Android, web, and server auth code flows.
  • Android SHA-1/SHA-256 entries for local debug and release signing.

Use the iOS reversed client ID as GOOGLE_IOS_URL_SCHEME.

Apple Sign-In

Set ios.appleSignIn: true in the config plugin. Apple returns name and email only on the first authorization for a user. Store any profile fields you need in your own backend or app state.

Apple Sign-In is supported on iOS and web. It is intentionally reported as unsupported_provider on Android.

Microsoft Entra ID

Create an app registration in Microsoft Entra ID and add redirect URIs:

  • iOS: msauth.<bundleIdentifier>://auth
  • Android: msauth://<androidPackage>/<clientId>
  • Web: your web origin, for example https://app.example.com

Use microsoftTenant for common, organizations, consumers, a tenant ID, or a B2C policy path. Use microsoftB2cDomain for Azure AD B2C.

Quick Start

import { Button, Text, View } from "react-native";
import {
  AuthError,
  type GoogleLoginOptions,
  useAuth,
} from "react-native-nitro-auth";

const googleOptions = {
  scopes: ["email", "profile"],
  forceAccountPicker: true,
} satisfies GoogleLoginOptions;

export function SignInScreen() {
  const { user, loading, login, logout, getAccessToken } = useAuth();

  async function signInWithGoogle() {
    try {
      await login("google", googleOptions);
    } catch (e) {
      const error = AuthError.from(e);
      console.warn(error.code, error.underlyingMessage);
    }
  }

  async function readToken() {
    const token = await getAccessToken();
    console.log(token);
  }

  return (
    <View>
      <Text>{user?.email ?? "Signed out"}</Text>
      <Button
        title={loading ? "Signing in..." : "Sign in with Google"}
        onPress={signInWithGoogle}
      />
      <Button title="Get access token" onPress={readToken} />
      <Button title="Sign out" onPress={logout} />
    </View>
  );
}

SocialButton

import { SocialButton } from "react-native-nitro-auth";

export function AuthButtons() {
  return (
    <>
      <SocialButton provider="google" />
      <SocialButton provider="apple" variant="black" />
      <SocialButton provider="microsoft" variant="outline" />
    </>
  );
}

AuthService

Use AuthService when you need auth outside React components.

import { AuthService } from "react-native-nitro-auth";

await AuthService.silentRestore();

const unsubscribe = AuthService.onAuthStateChanged((user) => {
  console.log(user?.email);
});

const tokensUnsubscribe = AuthService.onTokensRefreshed((tokens) => {
  console.log(tokens.expirationTime);
});

unsubscribe();
tokensUnsubscribe();

Login Options

await login("google", {
  scopes: ["email", "profile"],
  loginHint: "[email protected]",
  nonce: "opaque-nonce",
  useOneTap: true,
  forceAccountPicker: true,
  filterByAuthorizedAccounts: true,
  useLegacyGoogleSignIn: true,
  forceCodeForRefreshToken: true,
  hostedDomain: "company.com",
  requestVerifiedPhoneNumber: true,
});

await login("apple", {
  scopes: ["email", "name"],
  nonce: "opaque-nonce",
});

await login("microsoft", {
  scopes: ["openid", "profile", "email", "offline_access", "User.Read"],
  loginHint: "[email protected]",
  tenant: "organizations",
  prompt: "select_account",
});

| Option | Provider | Platform | Notes | | ---------------------------- | ------------ | ---------------- | ----------------------------------------------------------- | | scopes | All | iOS, Android, web | Requested OAuth scopes. Apple is unavailable on Android. | | loginHint | Google, Microsoft | iOS, Android, web | Prefills account selection when supported by the provider. | | nonce | Google, Apple | iOS, Android, web | Passed to provider ID-token flows when the SDK supports it. | | useOneTap | Google | Android | Enables Credential Manager auto-select. | | useSheet | Google | iOS | Compatibility alias; prefer forceAccountPicker. | | forceAccountPicker | Google | iOS, Android, web | Forces an account picker. Android uses the legacy chooser. | | filterByAuthorizedAccounts | Google | Android | Limits Credential Manager to authorized accounts. | | useLegacyGoogleSignIn | Google | Android | Uses legacy Google Sign-In for server auth code flows. | | forceCodeForRefreshToken | Google | Android | Forces a new server auth code on the legacy Google path. | | hostedDomain | Google | iOS, Android, web | Hints or filters Google Workspace hosted-domain accounts. | | openIDRealm | Google | iOS, web | Adds OpenID realm support where the SDK exposes it. | | requestVerifiedPhoneNumber | Google | Android | Requests verified phone number through Credential Manager. | | tenant | Microsoft | iOS, Android, web | Overrides configured tenant. | | prompt | Microsoft | iOS, Android, web | login, consent, select_account, or none. |

Incremental Scopes

const calendarScope = "https://www.googleapis.com/auth/calendar.readonly";

await requestScopes([calendarScope]);
await revokeScopes([calendarScope]);

On Android, incremental Google scope requests use the legacy Google Sign-In APIs because Credential Manager does not expose an equivalent existing-account scope query.

Storage Model

Native tokens are kept in memory by design. The package does not persist Microsoft refresh tokens or provider tokens to disk. Your app owns persistence and secure storage policy.

For app-managed persistence, store only the minimum state your product needs:

import { AuthService } from "react-native-nitro-auth";

const snapshot = {
  user: AuthService.currentUser,
  scopes: AuthService.grantedScopes,
  updatedAt: Date.now(),
};

On web, the default is also memory storage. You can opt into browser storage with:

extra: {
  nitroAuthWebStorage: "session", // "session", "local", or "memory"
  nitroAuthPersistTokensOnWeb: true,
}

Error Contract

All public async APIs throw AuthError, including provider errors surfaced by native and web AuthService implementations.

try {
  await AuthService.login("microsoft");
} catch (e) {
  const error = AuthError.from(e);
  switch (error.code) {
    case "cancelled":
      break;
    case "configuration_error":
      break;
    case "token_error":
      break;
    default:
      break;
  }
}

Known error codes:

type AuthErrorCode =
  | "cancelled"
  | "timeout"
  | "popup_blocked"
  | "network_error"
  | "configuration_error"
  | "not_signed_in"
  | "operation_in_progress"
  | "unsupported_provider"
  | "invalid_state"
  | "invalid_nonce"
  | "token_error"
  | "no_id_token"
  | "parse_error"
  | "refresh_failed"
  | "unknown";

underlyingMessage keeps the raw native or OAuth message when it differs from the stable code.

API Reference

Exports

export * from "react-native-nitro-auth";

Main exports:

  • useAuth()
  • AuthService
  • SocialButton
  • AuthError
  • isAuthErrorCode()
  • toAuthErrorCode()
  • AuthProvider
  • AuthUser
  • AuthTokens
  • LoginOptions
  • ProviderLoginOptions
  • LoginOptionsByProvider
  • GoogleLoginOptions
  • GoogleIOSLoginOptions
  • GoogleAndroidLoginOptions
  • GoogleWebLoginOptions
  • AppleLoginOptions
  • AppleIOSLoginOptions
  • AppleWebLoginOptions
  • MicrosoftLoginOptions
  • AuthLogin
  • TypedAuth

useAuth()

type UseAuthReturn = {
  user: AuthUser | undefined;
  scopes: string[];
  loading: boolean;
  error: AuthError | undefined;
  hasPlayServices: boolean;
  login(provider: AuthProvider, options?: LoginOptions): Promise<void>;
  logout(): void;
  requestScopes(scopes: string[]): Promise<void>;
  revokeScopes(scopes: string[]): Promise<void>;
  revokeAccess(): Promise<void>;
  getAccessToken(): Promise<string | undefined>;
  refreshToken(): Promise<AuthTokens>;
  silentRestore(): Promise<void>;
};

Strong Login Types

AuthService.login() and useAuth().login() infer the allowed option object from the provider argument. Provider-specific option types intentionally reject unsupported keys, so TypeScript can catch mistakes before they become native configuration bugs.

await AuthService.login("apple", {
  nonce: "opaque-nonce",
});

await AuthService.login("microsoft", {
  tenant: "organizations",
  prompt: "select_account",
});

Provider/platform option helpers are exported for config builders and AI-generated integrations:

import type {
  GoogleAndroidLoginOptions,
  GoogleIOSLoginOptions,
  MicrosoftLoginOptions,
} from "react-native-nitro-auth";

const androidGoogleOptions = {
  useOneTap: true,
  filterByAuthorizedAccounts: true,
  requestVerifiedPhoneNumber: true,
} satisfies GoogleAndroidLoginOptions;

const iosGoogleOptions = {
  hostedDomain: "company.com",
  openIDRealm: "https://example.com",
} satisfies GoogleIOSLoginOptions;

const microsoftOptions = {
  tenant: "organizations",
  prompt: "select_account",
} satisfies MicrosoftLoginOptions;

Examples of mistakes that TypeScript rejects:

await AuthService.login("apple", {
  tenant: "organizations",
});

await AuthService.login("microsoft", {
  nonce: "opaque-nonce",
});

AuthUser

type AuthUser = {
  provider: "google" | "apple" | "microsoft";
  email?: string;
  name?: string;
  photo?: string;
  idToken?: string;
  accessToken?: string;
  refreshToken?: string;
  serverAuthCode?: string;
  authorizationCode?: string;
  userId?: string;
  phoneNumber?: string;
  hostedDomain?: string;
  scopes?: string[];
  expirationTime?: number;
  underlyingError?: string;
};

Example App

The example app is the fastest way to verify setup and read a complete integration.

cp apps/example/.env.example apps/example/.env.local
bun install
bun run example:prebuild:clean
bun run example:ios
bun run example:android

The demo includes:

  • Provider cards for Google, Apple, and Microsoft.
  • Token and scope operations.
  • Silent restore, account picker, revoke access, and native logging actions.
  • Platform-gated controls for each supported Google, Apple, and Microsoft option.
  • App-owned disk snapshot example with react-native-nitro-storage.
  • Runtime smoke tests for the public API.

Troubleshooting

| Symptom | Check | | ------------------------------------- | -------------------------------------------------------------------------------- | | configuration_error on Google | Client ID is missing or wrong for the current platform | | Google works in debug but not release | Add release SHA-1/SHA-256 fingerprints to Google Cloud Console | | Android hasPlayServices is false | Use an emulator image with Google Play Services | | Apple email/name missing | Apple only returns these fields on first authorization | | Microsoft invalid_state | Redirect URI or app resume path is wrong, or an old auth redirect completed late | | Microsoft token_error | Check tenant, client ID, redirect URI, and requested scopes | | Web popup blocked | Call login() from a user gesture such as a button press | | operation_in_progress | A provider flow is already active; wait for it to finish or sign out |

Production Notes

  • Verify ID tokens on your backend. Client-side JWT parsing is for display and expiration hints only.
  • Store refresh tokens only in storage your app explicitly owns and secures.
  • Keep Google debug and release signing fingerprints in sync with your OAuth clients.
  • Add provider-specific redirect URIs for every environment.
  • Run the example app on iOS and Android before shipping provider config changes.

Release Checks

bun run release:preflight

The release preflight runs core-version verification, codegen, build, lint, typecheck, Jest, C++ tests, Expo dependency validation, Expo Doctor, Expo config introspection, package docs sync, pack dry run, and bun publish --dry-run --ignore-scripts.

CI runs the same preflight with registry publish dry-run disabled because GitHub pull-request jobs do not have npm publish credentials.

For faster local iteration before the full release dry run:

bun run check
bun run test:cpp
bun run --cwd packages/react-native-nitro-auth test:coverage -- --runInBand
bun run --cwd packages/react-native-nitro-auth test:cpp:coverage

Before shipping provider or native config changes, also verify the example app:

bun run example:prebuild
bun run example:android
bun run example:ios

License

MIT