• Stars
    star
    1,407
  • Rank 33,429 (Top 0.7 %)
  • Language
    JavaScript
  • License
    Other
  • Created almost 5 years ago
  • Updated 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A React Native library providing support for Apple Authentication on iOS and Android.

React Native Apple Authentication

NPM downloads NPM version License

Chat on Discord Follow on Twitter


A well typed React Native library providing support for Apple Authentication on iOS and Android, including support for all AppleButton variants.

apple-auth

Prerequisites to using this library

The @invertase/react-native-apple-authentication library will not work if you do not ensure the following:

  • You are using React Native version 0.60 or higher.

  • (iOS only) You have setup react-native iOS development environment on your machine (Will only work on Mac). If not, please follow the official React Native documentation for getting started: React Native getting started documentation.

  • (iOS only) You are using Xcode version 11 or higher. This will allow you to develop using iOS version 13 and higher, when the APIs for Sign In with Apple became available.

  • Once you're sure you've met the above, please follow our Initial development environment setup guide.

Version 2.0.0 breaking changes

Version 2 added Android support and introduced a few breaking changes with how methods are accessed. Please see the Migration Guide.

Installation

yarn add @invertase/react-native-apple-authentication

(cd ios && pod install)

You will not have to manually link this module as it supports React Native auto-linking.

Usage

Below are simple steps to help you get up and running. The implementation differs between iOS an Android, so if you're having trouble, be sure to look through the docs. Please skip and head to the full code examples noted below if you prefer to see a more complete implementation:

iOS

1. Initial set-up

Import the appleAuth (API documentation) module and the AppleButton (API documentation) exported member element from the @invertase/react-native-apple-authentication library. Setup an event handler (onPress) to kick start the authentication request.

// App.js

import React from 'react';
import { View } from 'react-native';
import { AppleButton } from '@invertase/react-native-apple-authentication';

async function onAppleButtonPress() {

}

function App() {
  return (
    <View>
      <AppleButton
        buttonStyle={AppleButton.Style.WHITE}
        buttonType={AppleButton.Type.SIGN_IN}
        style={{
          width: 160, // You must specify a width
          height: 45, // You must specify a height
        }}
        onPress={() => onAppleButtonPress()}
      />
    </View>
  );
}

2. Implement the login process

// App.js

import { appleAuth } from '@invertase/react-native-apple-authentication';

async function onAppleButtonPress() {
  // performs login request
  const appleAuthRequestResponse = await appleAuth.performRequest({
    requestedOperation: appleAuth.Operation.LOGIN,
    // Note: it appears putting FULL_NAME first is important, see issue #293
    requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
  });

  // get current authentication state for user
  // /!\ This method must be tested on a real device. On the iOS simulator it always throws an error.
  const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);

  // use credentialState response to ensure the user is authenticated
  if (credentialState === appleAuth.State.AUTHORIZED) {
    // user is authenticated
  }
}

3. Event Listener

Set up event listener for when user's credentials have been revoked.

// App.js

import React, { useEffect } from 'react';
import { View } from 'react-native';
import { appleAuth, AppleButton } from '@invertase/react-native-apple-authentication';

function App() {
  useEffect(() => {
    // onCredentialRevoked returns a function that will remove the event listener. useEffect will call this function when the component unmounts
    return appleAuth.onCredentialRevoked(async () => {
      console.warn('If this function executes, User Credentials have been Revoked');
    });
  }, []); // passing in an empty array as the second argument ensures this is only ran once when component mounts initially.

  return (
    <View>
      <AppleButton onPress={() => onAppleButtonPress()} />
    </View>
  );
}

4. Implement the logout process

There is an operation appleAuth.Operation.LOGOUT, however it does not work as expected and is not even being used by Apple in their example code. See this issue for more information

So it is recommended when logging out to just clear all data you have from a user, collected during appleAuth.Operation.LOGIN.

Android

1. Initial set-up

Make sure to correctly configure your Apple developer account to allow for proper authentication on Android. You can checkout our guide for more info.

// App.js

import React from 'react';
import { View } from 'react-native';
import { appleAuthAndroid, AppleButton } from '@invertase/react-native-apple-authentication';

async function onAppleButtonPress() {
}

// Apple authentication requires API 19+, so we check before showing the login button
function App() {
  return (
    <View>
      {appleAuthAndroid.isSupported && (
        <AppleButton
          buttonStyle={AppleButton.Style.WHITE}
          buttonType={AppleButton.Type.SIGN_IN}
          onPress={() => onAppleButtonPress()}
        />
      )}
    </View>
  );
}

2. Implement the login process

// App.js

import { appleAuthAndroid } from '@invertase/react-native-apple-authentication';
import 'react-native-get-random-values';
import { v4 as uuid } from 'uuid'

async function onAppleButtonPress() {
  // Generate secure, random values for state and nonce
  const rawNonce = uuid();
  const state = uuid();

  // Configure the request
  appleAuthAndroid.configure({
    // The Service ID you registered with Apple
    clientId: 'com.example.client-android',

    // Return URL added to your Apple dev console. We intercept this redirect, but it must still match
    // the URL you provided to Apple. It can be an empty route on your backend as it's never called.
    redirectUri: 'https://example.com/auth/callback',

    // The type of response requested - code, id_token, or both.
    responseType: appleAuthAndroid.ResponseType.ALL,

    // The amount of user information requested from Apple.
    scope: appleAuthAndroid.Scope.ALL,

    // Random nonce value that will be SHA256 hashed before sending to Apple.
    nonce: rawNonce,

    // Unique state value used to prevent CSRF attacks. A UUID will be generated if nothing is provided.
    state,
  });

  // Open the browser window for user sign in
  const response = await appleAuthAndroid.signIn();

  // Send the authorization code to your backend for verification
}

MacOS

This library works on MacOS 10.15+ if using in conjunction with react-native-macos.

Web (not react-native-web, but that may come as a follow-on, this is pure web at the moment)

1. Initial set-up

  • Ensure you follow the android steps above.
  • Install the web counterpart yarn add react-apple-signin-auth in your web project.

2. Implement the login process on web

import AppleSignin from 'react-apple-signin-auth';

/** Apple Signin button */
const MyAppleSigninButton = ({ ...rest }) => (
  <AppleSignin
    /** Auth options passed to AppleID.auth.init() */
    authOptions={{
      clientId: 'SAME AS ANDROID',
      redirectURI: 'SAME AS ANDROID',
      scope: 'email name',
      state: 'state',
      /** sha256 nonce before sending to apple to unify with native firebase behavior - https://github.com/invertase/react-native-apple-authentication/issues/28 */
      nonce: sha256('nonce'),
      /** We have to usePopup since we need clientSide authentication */
      usePopup: true,
    }}
    onSuccess={(response) => {
      console.log(response);
      // {
      //     "authorization": {
      //       "state": "[STATE]",
      //       "code": "[CODE]",
      //       "id_token": "[ID_TOKEN]"
      //     },
      //     "user": {
      //       "email": "[EMAIL]",
      //       "name": {
      //         "firstName": "[FIRST_NAME]",
      //         "lastName": "[LAST_NAME]"
      //       }
      //     }
      // }
    }}
  />
);

export default MyAppleSigninButton;

3. Verify serverside

  • Send the apple response to your server.
  • See Serverside Verification
  • Ensure that you pass the clientID as the web service ID, not the native app bundle. Since the project utilizes the service ID for authenticating web and android.

Serverside verification

Nonce

  • Based on the Firebase implementation guidelines the nonce provided to appleAuth.performRequest (iOS) and appleAuthAndroid.configure (Android) is automatically SHA256-hashed.
  • To verify the nonce serverside you first need to hash the nonce value, ie:
    crypto.createHash('sha256').update(nonce).digest('hex');
  • The nonce can then be easily compared serverside for extra security verification, ie:
    import crypto from 'crypto';
    import appleSigninAuth from 'apple-signin-auth';
    
    appleIdTokenClaims = await appleSigninAuth.verifyIdToken(id_token, {
      /** sha256 hex hash of raw nonce */
      nonce: nonce ? crypto.createHash('sha256').update(nonce).digest('hex') : undefined,
    });

API Reference Documentation

All API documentation is generated by typedoc, and is available in the typedocs folder

FAQs

  1. Why does full name and email return null?

     const appleAuthRequestResponse = await appleAuth.performRequest({
       requestedOperation: appleAuth.Operation.LOGIN,
       requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
     });
    • For testing purposes, to be receive these again, go to your device settings; Settings > Apple ID, iCloud, iTunes & App Store > Password & Security > Apps Using Your Apple ID, tap on your app and tap Stop Using Apple ID. You can now sign-in again and you'll receive the full name and `email.
    • Keep in mind you can always access the email property server-side by inspecting the id_token returned from Apple when verifying the user.
  2. How to change button language? (iOS)

    • Native Apple Button component reads language value from CFBundleDevelopmentRegion at Info.plist file. By changing CFBundleDevelopmentRegion value you can change default language for component.
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    • For supporting multi language, you can add CFBundleAllowMixedLocalizations key to Info.plist.
    <key>CFBundleAllowMixedLocalizations</key>
    <string>true</string>
  3. How do I get the email after the first login?

    • You can get the email address by parsing the JWT token that's returned from any authentication, like so:
    import { appleAuth } from '@invertase/react-native-apple-authentication';
    import jwt_decode from 'jwt-decode';
    
    const appleAuthRequestResponse = await appleAuth.performRequest({
      requestedOperation: appleAuth.Operation.LOGIN,
      requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME]
    });
    // other fields are available, but full name is not
    const { email, email_verified, is_private_email, sub } = jwt_decode(appleAuthRequestResponse.identityToken)

Troubleshooting

The operation couldnโ€™t be completed. (com.apple.AuthenticationServices.AuthorizationError error 1000.)
Case 1:

Check that the connection settings have been made correctly. The setup can be found here: Initial Setup

Case 2:

If you are using the function getCredentialStateForUser on a simulator, this error will always be triggered, for the reason that this function verifies the authenticity of the device.

You must test your code on a real device.

Case 3:

If you are using a simulator, go to Manage Apple Account.

Search for "Devices", select "Simulator" and press "Remove from Account".

show-devices

remove-from-manager

It should work fine.

"invalid_client" in Android webview

Make sure to read the Android services setup docs.

Case 1:

The clientId you passed to appleAuthAndroid.configure doesn't match the Service ID you setup in your Apple developer console.

Case 2:

Your Service ID is attached to the wrong Primary App ID, and therefore uses the incorrect Sign In with Apple key.

Case 3:

The redirectUri you passed to appleAuthAndroid.configure doesn't match one of the return URLs or domains/subdomains you added in your Apple developer console. The URL must match exactly, and cannot contain a query string.

License


Built and maintained by Invertase.

More Repositories

1

react-native-firebase

๐Ÿ”ฅ A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.
JavaScript
11,690
star
2

rdash-angular

AngularJS implementation of the RDash admin dashboard theme
HTML
4,686
star
3

react-native-material-design

React Native UI Components for Material Design
JavaScript
3,151
star
4

notifee

โš›๏ธ A feature rich notifications library for React Native.
TypeScript
1,841
star
5

react-native-firebase-starter

DEPRECATED: For RNFB v5 only.
JavaScript
1,172
star
6

melos

๐ŸŒ‹ A tool for managing Dart projects with multiple packages. With IntelliJ and Vscode IDE support. Supports automated versioning, changelogs & publishing via Conventional Commits.
Dart
1,155
star
7

react-native-google-mobile-ads

React Native Google Mobile Ads enables you to monetize your app with AdMob.
TypeScript
688
star
8

react-native-material-design-demo

An Android app to demonstrate react-native-material-design
JavaScript
494
star
9

react-native-notifee

Moved to https://github.com/invertase/notifee
TypeScript
465
star
10

docs.page

Instant Open Source docs with zero configuration.
TypeScript
463
star
11

firestore-ios-sdk-frameworks

โšก Precompiled Firestore iOS SDKs extracted from the Firebase iOS SDK repository release downloads for faster build times.
Ruby
444
star
12

stripe-firebase-extensions

Repository of Firebase Extensions built by Stripe.
TypeScript
437
star
13

react-query-firebase

React Query hooks for managing asynchronous operations with Firebase. Supports Authentication, Analytics, Firestore & Realtime Database.
TypeScript
390
star
14

denque

The fastest javascript implementation of a double-ended queue. Used by the official Redis, MongoDB, MariaDB & MySQL libraries for Node.js and many other libraries.
JavaScript
353
star
15

dart_edge

Run Dart on the Edge - supporting Vercel & Cloudflare Workers (more coming soon).
Dart
321
star
16

zapp.run

Zapp! A free online sandbox environment for building Flutter applications in the browser.
Dart
318
star
17

spec

โœ… A streamlined testing framework for Dart & Flutter.
Dart
302
star
18

dart_custom_lint

๐Ÿ’ก Easily write powerful Dart & Flutter lint rules for your projects or for users of your packages.
Dart
283
star
19

angular-toasty

A simple standalone AngularJS module with extensive features that provides growl-style alerts and messages for your app!
CSS
255
star
20

react-native-firebase-docs

DEPRECATED: For RNFB v5 only.
190
star
21

flutterfire_cli

A CLI to help with using FlutterFire in your Flutter applications.
Dart
172
star
22

github-action-dart-analyzer

A GitHub action to run Dart analyzer with annotation support.
TypeScript
168
star
23

react-native-firebase-authentication-example

An example React Native Firebase application integrating authentication.
TypeScript
141
star
24

conference-app

Dart
126
star
25

globe

๐ŸŒŽ The global deployment platform for Dart & Flutter applications.
Dart
124
star
26

dart_firebase_admin

๐Ÿ”ฅ A Firebase Admin SDK for Dart.
Dart
119
star
27

jet

โœˆ๏ธ Test your React Native modules e2e; mock-free and native testing code free.
TypeScript
98
star
28

react-native-gradle-plugin

A gradle plugin for React Native Android that simplifies and standardises build configurations (such as dependency versioning) for Projects & React Native modules.
Groovy
64
star
29

dart_docker

๐Ÿ‹ A Dart client for the Docker API via local unix socket.
Dart
45
star
30

flutter_desktop_webview_auth

WebView OAuth flows for desktop flutter apps
C++
34
star
31

dart_firebase_apis

๐Ÿ”ฅ Generated Firebase APIs for Dart. Additionally Includes private and unlisted APIs.
Dart
29
star
32

puppeteer-pool

Flexible Puppeteer Browser instance resource pooling.
JavaScript
29
star
33

nodejs-paddle-sdk

A fully typed Node.js library for integration with Paddle.
TypeScript
28
star
34

firebase-extensions

A collection of Firebase Extensions built by Invertase.
TypeScript
28
star
35

deeps

Performant utilities to manage deeply nested objects. get, set, flatten, diff etc.
JavaScript
26
star
36

dart-cli-utilities

โš’๏ธ A monorepo containing a collection of packages that provide useful functionality for building CLI applications in Dart.
Dart
21
star
37

samples

Collection of samples from our projects and tutorials.
Dart
20
star
38

cluster-key-slot

Generates CRC hashes for strings - for use by Node Redis clients to determine key slots.
JavaScript
19
star
39

genkit-samples

Invertase genkit samples
TypeScript
18
star
40

react-native-firebase-workshop-app

Showcasing React Native + Firebase
TypeScript
13
star
41

sails-firebase-auth

A SailsJS v1 JSON starter api with Firebase token authentication.
JavaScript
10
star
42

crc16

Native node addon to calculate CRC16 values.
C++
10
star
43

firebase-firestore-fields

Convert Firebase Cloud Firestore fields into a usable JavaScript format
JavaScript
10
star
44

react-native-auto-link-example

Init a React Native project with auto-linking ๐Ÿ”ฅ
Objective-C
10
star
45

react-native-template

Generic template for Invertase React Native projects
Objective-C
9
star
46

genkit-plugins

TypeScript
9
star
47

nodejs-google-java-format

Node.js repackaging of Google's native `google-java-format` tool.
JavaScript
8
star
48

remix-firebase-storage-file-handler

An upload handler for Remix using Firebase Storage
TypeScript
8
star
49

a2a

Async await to Array -> `const [error, value] = await A2A(fooPromise());`
JavaScript
7
star
50

dart_globe_examples

Repository containing various Dart examples for Globe.
6
star
51

firebase-extension-utilities

TypeScript
6
star
52

nx-dart

A Nx plugin, that adds support for developing Dart and Flutter packages in a Nx workspace.
TypeScript
6
star
53

babel-preset-react-native-syntax

๐Ÿ“ฆBabel preset providing syntax only plugins used by babel-preset-react-native - supports React Native ^0.56.0.
JavaScript
5
star
54

firebase-relationship

A simple Firebase Realtime Database relationship manager.
JavaScript
5
star
55

genkit-plugin-redis

A Redis Plugin for GenKit that adds Redis for efficient state storage, trace storage, caching, and rate limiting.
TypeScript
5
star
56

firebase-emulator-action

Shell
4
star
57

sails-ioredis

Redis adapter for waterline with sentinel and cluster support support (ioredis)
JavaScript
4
star
58

tutorials

๐ŸŽ“ A collection of open-source tutorials by us and the open-source community covering topics such as React Native and Firebase.
4
star
59

balanced-employee-ip-agreement

An English law and Open Source friendly Balanced Employee IP Agreement - providing a balanced approach to assigning control of intellectual property (IP) created by UK company employees. See releases for PDF/MD files
4
star
60

flutterfire_ui

Dart
3
star
61

wtfork

Subscribe to and publish events between parent and child node processes using the standard node event emitter api or call parent methods directly from the child process and vice versa.
JavaScript
3
star
62

redis-writable

Fast conversion of commands and args to redis protocol writables.
JavaScript
3
star
63

firebase-functions-python-old

[WIP] Firebase SDK for Cloud Functions and Python.
Python
3
star
64

llm-gcp

Python
3
star
65

extensions-quickstart-js

Firebase Extensions quick start examples
TypeScript
3
star
66

firebase_performance_flutter_example

Testing
Dart
2
star
67

meta

General guidelines and documentation for the Invertase GitHub org.
1
star
68

ios-sdk-10-issues

iOS SDK 10 Firebase Storage issues
Objective-C
1
star
69

react-custom-event

React hook for window CustomEvent
JavaScript
1
star
70

docker-react-native-firebase-android

Dockerfile
1
star
71

oss-discord-community

Nothing to see here.
1
star
72

.github

Default community health files for Invertase.
1
star