Skip to main content

Usage

Configure

configure() must run before any other method (typically in app startup or a root useEffect).

GoogleOneTapSignIn.configure({
webClientId: 'autoDetect', // or explicit Web client ID
iosClientId: undefined, // optional
offlineAccess: false,
hostedDomain: null,
nonce: null, // SHA-256 hex; auto-generated if omitted
scopes: null, // OAuth scope URLs
autoSelectOnSignIn: false,
})

Backend verification

This library returns Google-issued idToken and serverAuthCode values to JavaScript. Your backend must verify every token — never trust the client alone.

CheckAction
SignatureVerify RS256 with Google JWKS (https://www.googleapis.com/oauth2/v3/certs).
audMust equal your Web OAuth client ID.
issMust be accounts.google.com or https://accounts.google.com.
expReject expired tokens.
nonceIf you set configure({ nonce }), verify the JWT nonce claim matches your server-issued value.
hdIf you use hostedDomain, validate the JWT hd claim on the server.
serverAuthCodeExchange only on your backend with the client secret; never log full codes in analytics or UI.

Full checklist: SECURITY.md in the repository.

iOS silent signIn() and serverAuthCode

With offlineAccess: true, iOS silent signIn() / restore returns serverAuthCode: null. Use createAccount() or presentExplicitSignIn() for the initial offline grant that returns a code.

Same cascade as the Usage guide and Quick Start:

  1. checkPlayServices() (Android)
  2. signIn() — silent / restore
  3. createAccount() — if no saved credential
  4. presentExplicitSignIn() — explicit UI

Use helpers to branch on response type:

import {
isSuccessResponse,
isNoSavedCredentialFoundResponse,
isCancelledResponse,
isErrorWithCode,
statusCodes,
} from 'react-native-nitro-google-signin'

OAuth scopes (more access)

Request Google API permissions beyond basic profile / ID token. Always use full scope URLs (for example https://www.googleapis.com/auth/calendar.readonly), not short names.

offlineAccess: true required for serverAuthCode

To receive a serverAuthCode — from sign-in (response.data.serverAuthCode) or from requestScopes() — you must pass offlineAccess: true in configure(). The default is false; without it, serverAuthCode is always null even when scopes are granted.

For on-device Google API calls after requestScopes(), use the returned accessToken — that works with or without offlineAccess.

ApproachAPIWhen to use
At first sign-inconfigure({ scopes, offlineAccess })You know required scopes before the user signs in. Consent may appear during sign-in.
LaterrequestScopes(scopes)User is already signed in; request extra access when they use a feature (e.g. “Connect calendar”).
Inspect grantedgetCurrentUser()Check scopes before calling requestScopes() so existing users are not prompted again.

Option A — scopes at configure time

Pass scopes in configure(). offlineAccess: true is required when your backend needs a serverAuthCode to exchange for refresh tokens:

import {
GoogleOneTapSignIn,
isNoSavedCredentialFoundResponse,
isSuccessResponse,
} from 'react-native-nitro-google-signin'

const CALENDAR_READONLY = 'https://www.googleapis.com/auth/calendar.readonly'

GoogleOneTapSignIn.configure({
webClientId: 'autoDetect',
scopes: [CALENDAR_READONLY],
offlineAccess: true,
})

const signInWithScopesUpFront = async () => {
await GoogleOneTapSignIn.checkPlayServices()
let response = await GoogleOneTapSignIn.signIn()

if (isNoSavedCredentialFoundResponse(response)) {
response = await GoogleOneTapSignIn.createAccount()
}

if (isSuccessResponse(response)) {
const { user, idToken, serverAuthCode } = response.data
// idToken — verify on your backend
// serverAuthCode — exchange on backend when offlineAccess is true
console.log(user.email, idToken, serverAuthCode)
}
}

Option B — scopes after sign-in (requestScopes)

Sign in first, then call requestScopes() when a feature needs extra Google API access. The user may see a consent screen. Use the returned accessToken to call Google APIs from the device. Set offlineAccess: true only if you also need a serverAuthCode for your backend:

import {
GoogleOneTapSignIn,
isSuccessResponse,
} from 'react-native-nitro-google-signin'

const CALENDAR_READONLY = 'https://www.googleapis.com/auth/calendar.readonly'

GoogleOneTapSignIn.configure({
webClientId: 'autoDetect',
// offlineAccess: true, // only if you need serverAuthCode for your backend
})

const signInThenRequestScopesLater = async () => {
await GoogleOneTapSignIn.checkPlayServices()
const response = await GoogleOneTapSignIn.signIn()

if (!isSuccessResponse(response)) return

const { user, idToken } = response.data
// Signed in with basic access — calendar not requested yet
console.log(user.email, idToken)
}

const enableCalendarAccess = async () => {
const current = GoogleOneTapSignIn.getCurrentUser()
if (current?.scopes.includes(CALENDAR_READONLY)) {
// Already granted — skip consent UI
return
}

const { accessToken, serverAuthCode } = await GoogleOneTapSignIn.requestScopes([
CALENDAR_READONLY,
])

if (accessToken) {
// Call Google APIs from the device
await fetch('https://www.googleapis.com/calendar/v3/users/me/calendarList', {
headers: { Authorization: `Bearer ${accessToken}` },
})
}

if (serverAuthCode) {
// Send to your backend to store refresh tokens (requires offlineAccess: true)
await fetch('https://your-api.example/auth/google/exchange', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ serverAuthCode }),
})
}
}
Requires prior sign-in

requestScopes() only works after a successful sign-in (configure() + active session). Call it from a button handler or feature gate, not before the user has signed in. Sign-in can use the imperative API or useGoogleSignInFromButton.

accessToken vs serverAuthCode
  • accessToken — for on-device Google API calls. Returned when consent succeeds, even with offlineAccess: false.
  • serverAuthCode — for your backend to exchange for refresh tokens. Requires offlineAccess: true in configure(). Without it, consent may succeed but serverAuthCode stays null.
Combine both

You can pass baseline scopes in configure({ scopes }) and call requestScopes() later for additional scopes the user opts into.

See also requestScopes() in the API reference. Example apps: bare example/App.tsx · Expo example-expo/App.tsx.

Access tokens (getTokens)

Use getTokens() when you need the current user's ID token and OAuth access token after sign-in — for example when migrating from @react-native-google-signin/google-signin:

import {
GoogleOneTapSignIn,
isSuccessResponse,
isErrorWithCode,
statusCodes,
} from 'react-native-nitro-google-signin'

const signInAndFetchTokens = async () => {
const response = await GoogleOneTapSignIn.signIn()

if (!isSuccessResponse(response)) return

try {
const { idToken, accessToken } = await GoogleOneTapSignIn.getTokens()
// Prefer verifying idToken on your backend, or exchange serverAuthCode
console.log(idToken.slice(0, 16), accessToken.slice(0, 16))
} catch (e) {
if (isErrorWithCode(e) && e.code === statusCodes.SIGN_IN_REQUIRED) {
// User session expired — run sign-in again
}
}
}
PlatformBehavior
AndroidReturns the ID token cached from the last Credential Manager sign-in plus a fresh access token from AuthorizationClient. May show a consent UI if scopes were not yet authorized.
iOSUses the AppAuth session behind GIDSignIn. Refreshes tokens from Google when expired or after clearCachedAccessToken().
Backend auth

Google recommends verifying the idToken on your server or exchanging a serverAuthCode (with offlineAccess: true) for refresh tokens. Client-side access tokens are mainly for calling Google APIs from the device.

Invalid access token (clearCachedAccessToken)

If a Google API returns 401 or otherwise indicates the access token is stale, clear the local cache and fetch again:

try {
await callGoogleApi(accessToken)
} catch (e) {
if (isInvalidTokenError(e)) {
await GoogleOneTapSignIn.clearCachedAccessToken(accessToken)
const { accessToken: freshToken } = await GoogleOneTapSignIn.getTokens()
await callGoogleApi(freshToken)
}
}
PlatformclearCachedAccessTokenNext getTokens()
AndroidRemoves the token from AuthorizationClient's local cacheFetches a new access token from Google
iOSMarks the AppAuth session with setNeedsTokenRefresh()Performs a network refresh and returns new tokens

On iOS, calling getTokens() twice in a row without clearing first may return the same access token while it is still valid — that is expected. Call clearCachedAccessToken() first when you know the token is invalid.

See getTokens() and clearCachedAccessToken() in the API reference.

Sign out and revoke

await GoogleOneTapSignIn.signOut()

await GoogleOneTapSignIn.revokeAccess(userEmailOrId)
PlatformrevokeAccess
AndroidResolves the account by email or OneTapUser.id.
iOSRevokes only the current signed-in session. Throws if userEmailOrId does not match the active user — call signIn() first when revoking a specific stored account.
Google Workspace (hostedDomain)

Client-side domain filtering is a convenience only. Always validate the JWT hd claim on your backend. On Android, GoogleSignInButton with signInBehavior="buttonFlow" validates hd after sign-in; Credential Manager flows filter at request time.

Errors

Thrown errors are GoogleSignInError with a code from statusCodes:

CodeMeaning
ONE_TAP_START_FAILEDFlow could not start
PLAY_SERVICES_NOT_AVAILABLEAndroid Play Services issue
IN_PROGRESSAnother sign-in in progress
SIGN_IN_REQUIREDUser must sign in
SIGN_IN_CANCELLEDUser cancelled (authorization UI)
DEVELOPER_ERRORAndroid OAuth misconfiguration (SHA-1 / package / client ID)
try {
await GoogleOneTapSignIn.signIn()
} catch (e) {
if (isErrorWithCode(e) && e.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
// handle
}
}

Cancelled responses (not throws) use isCancelledResponse(response). On Android production builds, type: 'cancelled' after picking an account often means a missing Play App Signing SHA-1 — see troubleshooting.

Native sign-in button

See Google Sign-In button.