/* eslint-disable no-console */ /** * Copyright (c) 2016-present Invertase Limited & Contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this library except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import React, { useState, useEffect } from 'react'; import { StyleSheet, View, Text } from 'react-native'; import { decode } from 'base-64'; import { jwtDecode } from 'jwt-decode'; import { appleAuth, AppleButton } from '@invertase/react-native-apple-authentication'; // polyfill for "atob" so that jwt.decode will work global.atob = decode; /** * You'd technically persist this somewhere for later use. */ let userId = 'unknown'; let userName = 'unknown'; let userEmail = 'unknown'; /** * Fetches the credential state for the current user, if any, and updates state on completion. */ async function fetchAndUpdateCredentialState(updateCredentialStateForUser) { if (userId === 'unknown') { updateCredentialStateForUser('User not signed in.'); } else { const credentialState = await appleAuth.getCredentialStateForUser(userId); if (credentialState === appleAuth.State.AUTHORIZED) { updateCredentialStateForUser('AUTHORIZED'); } else { updateCredentialStateForUser(credentialState); } } } async function onUpdateCredentialStateButtonPress(updateCredentialStateForUser) { console.warn('Beginning Credential Update'); fetchAndUpdateCredentialState(updateCredentialStateForUser).catch(error => updateCredentialStateForUser(`Error: ${error.code}`), ); } /** * Starts the Sign In flow. */ async function onAppleButtonPress(updateCredentialStateForUser) { console.warn('Beginning Apple Authentication'); // start a login request try { const appleAuthRequestResponse = await appleAuth.performRequest({ requestedOperation: appleAuth.Operation.LOGIN, requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME], }); console.log('appleAuthRequestResponse', appleAuthRequestResponse); const { user: newUser, email, fullName, identityToken, nonce, realUserStatus /* etc */, } = appleAuthRequestResponse; userId = newUser; email ? (userEmail = email) : (userEmail = 'unknown'); fullName && fullName.givenName && fullName.familyName ? (userName = `${fullName.givenName} ${fullName.familyName}`) : (userName = 'unknown'); // The email and fullName are only provided on the first sign in to an app. // But, we can get the email from the JWT every time if we decode it. const decoded = jwtDecode(identityToken); console.log('decoded token: ', decoded); userEmail === 'unknown' && decoded.email ? (userEmail = decoded.email) : (userEmail = 'unknown'); fetchAndUpdateCredentialState(updateCredentialStateForUser).catch(error => updateCredentialStateForUser(`Error: ${error.code}`), ); if (identityToken) { // e.g. sign in with Firebase Auth using `nonce` & `identityToken` console.log(nonce, identityToken); } else { // no token - failed sign-in? } if (realUserStatus === appleAuth.UserStatus.LIKELY_REAL) { console.log("I'm a real person!"); } console.warn(`Apple Authentication Completed, ${userId}, ${email}`); } catch (error) { if (error.code === appleAuth.Error.CANCELED) { console.warn('User canceled Apple Sign in.'); } else { console.error(error); } } } export default function RootComponent() { const [credentialStateForUser, updateCredentialStateForUser] = useState(-1); useEffect(() => { if (!appleAuth.isSupported) return; fetchAndUpdateCredentialState(updateCredentialStateForUser).catch(error => updateCredentialStateForUser(`Error: ${error.code}`), ); }, []); useEffect(() => { if (!appleAuth.isSupported) return; return appleAuth.onCredentialRevoked(async () => { console.warn('Credential Revoked'); fetchAndUpdateCredentialState(updateCredentialStateForUser).catch(error => updateCredentialStateForUser(`Error: ${error.code}`), ); }); }, []); if (!appleAuth.isSupported) { return ( Apple Authentication is not supported on this device. ); } return ( onUpdateCredentialStateButtonPress(updateCredentialStateForUser)} > Credential State {credentialStateForUser} onUpdateCredentialStateButtonPress(updateCredentialStateForUser)} > User Information {`id: ${userId} / email: ${userEmail} / name: ${userName}`} Buttons Continue Styles onAppleButtonPress(updateCredentialStateForUser)} /> onAppleButtonPress(updateCredentialStateForUser)} /> onAppleButtonPress(updateCredentialStateForUser)} /> Sign-in Styles onAppleButtonPress(updateCredentialStateForUser)} /> onAppleButtonPress(updateCredentialStateForUser)} /> onAppleButtonPress(updateCredentialStateForUser)} /> ); } const styles = StyleSheet.create({ appleButton: { width: 200, height: 60, margin: 10, }, header: { margin: 10, marginTop: 30, fontSize: 18, fontWeight: '600', }, container: { flex: 1, justifyContent: 'center', backgroundColor: 'pink', }, horizontal: { flexDirection: 'column', justifyContent: 'center', alignItems: 'center', padding: 10, }, });