Types
Every type, enum and type guard exported by react-native-oauth-essentials. Import types with import type, and
enums and functions with a normal import:
import { CredentialsType, CredentialError, isCredentialError } from 'react-native-oauth-essentials';
import type { GoogleIdCredentialResult, GoogleSignInOptions } from 'react-native-oauth-essentials';
The Platform column says where a property has an effect. Options that do nothing on the current platform are ignored, with a warning in development (see Development warnings).
For the error codes, their causes and how to handle them, see Errors.
Return type of each method
| Method | Resolves |
|---|---|
googleSignIn | GoogleIdCredentialResult | CancelledCredentialResult |
googleSilentSignIn | GoogleIdCredentialResult | CancelledCredentialResult |
signOut | boolean (always true) |
getPassword | PasswordCredentialResult | CancelledCredentialResult |
passwordSignIn | boolean (saved or not; always false on iOS) |
appleSignIn | AppleIdCredentialResult | WebAppleIdCredentialResult | CancelledCredentialResult |
getAppleIdCredentialState | AppleIdCredentialState |
hybridSignIn | HybridSignInResult |
createPassKey | PassKeyCredentialResult | CancelledCredentialResult |
getPassKey | PassKeyCredentialResult | CancelledCredentialResult |
cancelPassKeyAutoFill | boolean (whether a pending AutoFill request was cancelled) |
oauthSignIn | OAuthCredentialResult | CancelledCredentialResult |
addCredentialSuccessListener / addCredentialFailureListener / addAppleIdCredentialRevokedListener | EventSubscription (from react-native, call .remove()) |
Every result has a type field from CredentialsType, so a switch (result.type) narrows data.
Options
GoogleClientIds
Google OAuth client ids per platform, all from the same Google Cloud project. Taken by googleSignIn,
googleSilentSignIn and hybridSignIn. Both ids are optional: a missing id is read from the app config, which the
Expo plugin writes from its options or the Firebase files (see
Google client ids).
type GoogleClientIds = {
iosClientId?: string;
webClientId?: string;
};
| Property | Type | Platform | Description |
|---|---|---|---|
iosClientId | string | iOS | iOS client id (created with the bundle id). When missing, iOS reads GIDClientID from Info.plist, then CLIENT_ID from the Firebase GoogleService-Info.plist. None rejects with CONFIGURATION_ERROR |
webClientId | string | Both | Android: the client id passed to Credential Manager. When missing, Android reads the com.oauthessentials.GOOGLE_WEB_CLIENT_ID meta-data of AndroidManifest.xml, then the default_web_client_id string generated by the Firebase google-services Gradle plugin. None rejects with CONFIGURATION_ERROR. iOS: the default serverClientId (idToken audience and serverAuthCode); when missing, iOS reads GIDServerClientID from Info.plist |
GoogleClientId
A GoogleClientIds object, or a single client id string. A string is used as is on both
platforms, so it must be the iOS client id on iOS and the web client id on Android.
type GoogleClientId = string | GoogleClientIds;
// Ids in the app config (Expo plugin, Info.plist, AndroidManifest or Firebase files)
await googleSignIn();
await googleSignIn({ mode: 'button' });
// Ids in code
const GOOGLE_CLIENT_IDS: GoogleClientIds = {
iosClientId: '1234-abcd.apps.googleusercontent.com',
webClientId: '5678-efgh.apps.googleusercontent.com',
};
await googleSignIn(GOOGLE_CLIENT_IDS, { mode: 'button' });
GoogleSignInOptions
Options of googleSignIn and googleSilentSignIn.
type GoogleSignInOptions = {
authorizedAccounts?: boolean;
autoSelectEnabled?: boolean;
mode?: 'bottomSheet' | 'button';
nonce?: string;
hint?: string;
hostedDomain?: string;
scopes?: string[];
offlineAccess?: boolean;
serverClientId?: string;
};
| Property | Type | Default | Platform | Description |
|---|---|---|---|---|
authorizedAccounts | boolean | false | Android | Only show accounts that already signed in to the app |
autoSelectEnabled | boolean | false | Android | Sign in without UI when a single authorized account is available |
mode | 'bottomSheet' | 'button' | 'bottomSheet' | Android | bottomSheet shows the Credential Manager sheet and, unless authorizedAccounts is set, falls back to button when no credential is available (no account, or the sheet is in cooldown after being dismissed). button always shows the "Sign in with Google" flow: use it for a button tap |
nonce | string | - | Both | Embedded as is in the idToken, so your backend can prevent replay attacks. Ignored by googleSilentSignIn on iOS |
hint | string | - | iOS | Email to preselect in the Google page |
hostedDomain | string | - | Both | Restricts sign in to a Google Workspace domain. On Android it only applies to the button flow and to the authorization step, not to the bottom sheet |
scopes | string[] | - | Both | Additional OAuth scopes. iOS: requested during sign in; accessToken and grantedScopes are always returned. Android: requested in a second step (Authorization API, may show a consent screen); without scopes/offlineAccess, accessToken and grantedScopes are null |
offlineAccess | boolean | false | Android | Returns a serverAuthCode your backend can exchange for a refresh token. On iOS serverAuthCode is returned whenever serverClientId is set |
serverClientId | string | webClientId | Both | iOS: web (server) client id, used as the idToken audience and for serverAuthCode. Android: client id the serverAuthCode is issued for |
const options: GoogleSignInOptions = {
mode: 'button',
nonce: 'random-nonce',
scopes: ['https://www.googleapis.com/auth/drive.readonly'],
};
await googleSignIn(options);
HybridSignInOptions
Options of hybridSignIn. Same shape as GoogleSignInOptions, but only some fields are used:
type HybridSignInOptions = GoogleSignInOptions;
| Property | iOS | Android |
|---|---|---|
nonce | Used, for Apple ID | Used, for Google ID |
authorizedAccounts, autoSelectEnabled | Ignored | Used, for Google ID |
mode, hint, scopes, offlineAccess, hostedDomain, serverClientId | Ignored | Ignored |
AppleSignInOptions
Options of appleSignIn. iOS only: on Android put the nonce and state in your androidWebUrl.
type AppleSignInOptions = {
nonce?: string;
state?: string;
};
| Property | Type | Platform | Description |
|---|---|---|---|
nonce | string | iOS | Passed as is to Apple and embedded in the idToken. Firebase and Supabase expect the SHA-256 of the raw nonce here |
state | string | iOS | Opaque value returned in AppleIdCredentialResult.data.state |
PasskeyOptions
Options of createPassKey and getPassKey.
type PasskeyOptions = {
requestJson: string;
preferImmediatelyAvailableCredentials?: boolean;
mediation?: 'modal' | 'autofill';
};
| Property | Type | Default | Platform | Description |
|---|---|---|---|---|
requestJson | string | required | Both | WebAuthn options JSON from your server: PublicKeyCredentialCreationOptions for createPassKey, PublicKeyCredentialRequestOptions for getPassKey |
preferImmediatelyAvailableCredentials | boolean | false | Android | Only offer credentials already available on the device. iOS modal requests always behave this way |
mediation | 'modal' | 'autofill' | 'modal' | iOS 16+ | autofill (getPassKey only) shows passkeys in the QuickType bar of a text field with textContentType="username" instead of a sheet. See Passkeys |
const options: PasskeyOptions = {
requestJson: JSON.stringify({
challenge: 'base64url-challenge',
rp: { name: 'Your App', id: 'yourapp.com' },
user: { id: 'base64url-user-id', name: 'user@example.com', displayName: 'User Name' },
pubKeyCredParams: [{ type: 'public-key', alg: -7 }],
authenticatorSelection: { userVerification: 'required' },
}),
};
await createPassKey(options);
OAuthSignInOptions
Options of oauthSignIn.
type OAuthSignInOptions = {
authorizationEndpoint: string;
clientId: string;
redirectUri?: string;
scopes?: string[];
additionalParameters?: Record<string, string>;
tokenEndpoint?: string;
usePKCE?: boolean;
prefersEphemeralSession?: boolean;
};
| Property | Type | Default | Platform | Description |
|---|---|---|---|---|
authorizationEndpoint | string | required | Both | Authorization url of the provider |
clientId | string | required | Both | OAuth client id |
redirectUri | string | OAUTH_REDIRECT_URI | Both | Where the provider redirects. Without a scheme it rejects with CONFIGURATION_ERROR |
scopes | string[] | - | Both | Sent as scope, space separated |
additionalParameters | Record<string, string> | - | Both | Extra authorization parameters, like prompt, login_hint or nonce. They may override scope. response_type, client_id, redirect_uri, state, code_challenge and code_challenge_method are set by the library and ignored here, with a warning in development |
tokenEndpoint | string | - | Both | When set, the code is exchanged for tokens on the device. Leave it out to exchange the code on your backend (recommended for confidential clients) |
usePKCE | boolean | true | Both | Sends a PKCE S256 code_challenge |
prefersEphemeralSession | boolean | false | iOS | Do not share cookies with Safari |
Results
GoogleIdCredentialResult
Resolved by googleSignIn, googleSilentSignIn and hybridSignIn (Android).
type GoogleIdCredentialResult = {
type: CredentialsType.GOOGLE_ID;
data: {
id: string;
idToken: string;
displayName: string;
givenName: string;
familyName: string;
email?: string;
profilePictureUri?: string | null;
phoneNumber?: string | null;
accessToken?: string | null;
serverAuthCode?: string | null;
grantedScopes?: string[] | null;
};
};
| Field | Type | Platform | Description |
|---|---|---|---|
id | string | Both | iOS: Google user id (the idToken sub). Android: the account email |
idToken | string | Both | JWT to verify on your backend |
displayName | string | Both | Full name |
givenName | string | Both | First name |
familyName | string | Both | Last name |
email | string | Both | Account email |
profilePictureUri | string | null | Both | Profile picture url. iOS: 200px url, or "" without picture |
phoneNumber | string | null | Android | Phone number, when shared |
accessToken | string | null | Both | iOS: always returned. Android: only when scopes or offlineAccess were requested |
grantedScopes | string[] | null | Both | Scopes granted to accessToken |
serverAuthCode | string | null | Both | Android: with offlineAccess. iOS: when serverClientId (or webClientId) is set, never on googleSilentSignIn |
PasswordCredentialResult
Resolved by getPassword and hybridSignIn.
type PasswordCredentialResult = {
type: CredentialsType.PASSWORD;
data: {
username: string;
password: string;
};
};
| Field | Type | Description |
|---|---|---|
username | string | Saved username or email |
password | string | Saved password |
AppleIdCredentialResult
Resolved by appleSignIn and hybridSignIn on iOS.
type AppleIdCredentialResult = {
type: CredentialsType.APPLE_ID;
data: {
idToken: string;
authorizationCode: string;
user: string;
email: string;
fullName: string;
likelyReal: boolean;
state?: string | null;
};
};
| Field | Type | Description |
|---|---|---|
idToken | string | JWT to verify on your backend |
authorizationCode | string | Short lived code your backend can exchange with Apple |
user | string | Stable user id for the app (same across reinstalls). Pass it to getAppleIdCredentialState |
email | string | Email, possibly a private relay address. Apple only sends it on the first authorization |
fullName | string | Full name. Apple only sends it on the first authorization |
likelyReal | boolean | Apple considers the user likely a real person |
state | string | null | The state passed in AppleSignInOptions |
Apple only sends email and fullName the first time a user authorizes the app. appleSignIn keeps the first result
of each user in memory (until the app is killed) and fills them in later results, but save them on your backend on the
first sign in.
WebAppleIdCredentialResult
Resolved by appleSignIn on Android, with the url your backend redirected to at the end of the Apple web flow.
type WebAppleIdCredentialResult = {
type: CredentialsType.WEB_APPLE_ID;
data: {
url: string;
scheme: string | null;
host: string | null;
path: string | null;
query: string | null;
};
};
| Field | Type | Description |
|---|---|---|
url | string | Full redirect url |
scheme | string | null | Url scheme, e.g. com.example.app |
host | string | null | Url host, e.g. oauth |
path | string | null | Url path, e.g. /callback |
query | string | null | Query string, with whatever your backend put there |
const params = new URLSearchParams(result.data.query ?? '');
const token = params.get('token');
PassKeyCredentialResult
Resolved by createPassKey and getPassKey.
type PassKeyCredentialResult = {
type: CredentialsType.PASSKEY;
data: string;
};
| Field | Type | Description |
|---|---|---|
data | string | WebAuthn response JSON to send to your server: the registration response (createPassKey) or the authentication response (getPassKey), binary fields in base64url |
OAuthCredentialResult
Resolved by oauthSignIn.
type OAuthCredentialResult = {
type: CredentialsType.OAUTH;
data: {
code: string;
state: string;
redirectUri: string;
codeVerifier: string | null;
params: Record<string, string>;
tokens: Record<string, unknown> | null;
};
};
| Field | Type | Description |
|---|---|---|
code | string | Authorization code |
state | string | The state generated by the library, already checked against the redirect |
redirectUri | string | Redirect uri used in the request. Send it with the code to your backend |
codeVerifier | string | null | PKCE verifier, null when usePKCE is false |
params | Record<string, string> | Every query and fragment parameter of the redirect |
tokens | Record<string, unknown> | null | Token endpoint JSON response, only when tokenEndpoint is set |
const result = await oauthSignIn({ authorizationEndpoint, clientId, scopes: ['openid', 'email'] });
if (result.type === CredentialsType.OAUTH) {
await api.exchangeCode(result.data.code, result.data.codeVerifier, result.data.redirectUri);
}
CancelledCredentialResult
Resolved by every sign in method when the user dismisses the UI (and in the other cases listed per method in Methods). It is not an error: show the sign in screen again or other options.
type CancelledCredentialResult = {
type: CredentialsType.CANCELLED;
data: null;
};
HybridSignInResult
Resolved by hybridSignIn. Apple ID only on iOS, Google ID only on Android.
type HybridSignInResult =
| AppleIdCredentialResult
| GoogleIdCredentialResult
| PasswordCredentialResult
| CancelledCredentialResult;
Events
CredentialSuccessEvent
Received by addCredentialSuccessListener. Same shape as the resolved result, including
CANCELLED.
type CredentialSuccessEvent = {
type: string;
data: Object;
};
| Field | Type | Description |
|---|---|---|
type | string | A CredentialsType value |
data | object | null | The result data (null for CANCELLED) |
CredentialFailureEvent
Received by addCredentialFailureListener. See
which errors are emitted.
type CredentialFailureEvent = {
code: CredentialErrorCode;
message: string;
};
| Field | Type | Description |
|---|---|---|
code | CredentialErrorCode | The error code |
message | string | Native error message |
Enums
CredentialsType
The type of every result.
| Value | Result | Resolved by |
|---|---|---|
GOOGLE_ID | GoogleIdCredentialResult | googleSignIn, googleSilentSignIn, hybridSignIn (Android) |
PASSWORD | PasswordCredentialResult | getPassword, hybridSignIn |
APPLE_ID | AppleIdCredentialResult | appleSignIn (iOS), hybridSignIn (iOS) |
WEB_APPLE_ID | WebAppleIdCredentialResult | appleSignIn (Android) |
PASSKEY | PassKeyCredentialResult | createPassKey, getPassKey |
OAUTH | OAuthCredentialResult | oauthSignIn |
CANCELLED | CancelledCredentialResult | Every sign in method |
const result = await hybridSignIn();
switch (result.type) {
case CredentialsType.APPLE_ID:
await api.signInWithApple(result.data.idToken);
break;
case CredentialsType.GOOGLE_ID:
await api.signInWithGoogle(result.data.idToken);
break;
case CredentialsType.PASSWORD:
await api.signIn(result.data.username, result.data.password);
break;
case CredentialsType.CANCELLED:
showSignInScreen();
break;
}
AppleIdCredentialState
Resolved by getAppleIdCredentialState (iOS).
| Value | Meaning | What to do |
|---|---|---|
AUTHORIZED | The user is still signed in to the app with Apple ID | Nothing |
REVOKED | The user stopped using Apple ID with the app | Sign them out |
NOT_FOUND | No credential for this user id | Sign them out |
TRANSFERRED | The app was transferred to another team | Migrate the user id |
CredentialError
The code of every rejection. Each code, its causes and how to handle it are in Errors.
| Value | Meaning |
|---|---|
CONFIGURATION_ERROR | The app is misconfigured (missing Google client id or URL scheme, invalid redirectUri) |
NOT_SUPPORTED_ERROR | The OS version, missing Play Services or the platform does not support the method |
NO_SIGN_IN_AVAILABLE | There is no credential to return (no account, passkey or previous sign in) |
BROWSER_UNAVAILABLE | The browser session could not be opened |
NO_ACTIVITY_ERROR | No Android activity or iOS view controller to present the UI |
SIMULTANEOUS_CALL_ERROR | iOS: the same method is still waiting for the previous call |
NETWORK_ERROR | oauthSignIn: the token endpoint request failed |
INVALID_RESULT_ERROR | The provider failed or returned something unexpected |
NO_PLAY_SERVICES_ERROR | Deprecated, never used. Missing Play Services rejects with NOT_SUPPORTED_ERROR |
Error types
CredentialErrorCode
String union of the CredentialError values. Accepts both the enum members and their strings.
type CredentialErrorCode = `${CredentialError}`;
// 'CONFIGURATION_ERROR' | 'NOT_SUPPORTED_ERROR' | 'NO_SIGN_IN_AVAILABLE' | ...
OauthEssentialsError
What the promises of the library reject with: an Error with a code. The native error text is in message.
type OauthEssentialsError<C extends CredentialErrorCode = CredentialErrorCode> = Error & { code: C };
isCredentialError(error, code?)
Type guard for catch blocks. Returns true when error is an object whose code is a CredentialError value, and
equals code when given. It never throws.
function isCredentialError<C extends CredentialErrorCode = CredentialErrorCode>(
error: unknown,
code?: C
): error is OauthEssentialsError<C>;
import { googleSignIn, isCredentialError, CredentialError } from 'react-native-oauth-essentials';
try {
await googleSignIn();
} catch (e) {
if (isCredentialError(e, CredentialError.CONFIGURATION_ERROR)) console.error(e.message);
else if (isCredentialError(e)) report(e.code, e.message);
else throw e;
}