Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(auth): Add Expo support for phone auth #6167 #6472

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/auth/phone-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ For reliable automated testing, you may want to disable both automatic and fallb

Ensure that all parts of step 1 and 2 from [the official firebase Android phone auth docs](https://firebase.google.com/docs/auth/android/phone-auth#enable-phone-number-sign-in-for-your-firebase-project) have been followed.

# Expo Setup

To use phone auth in an expo app, add the `@react-native-firebase/auth` config plug-in to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) section of your `app.json`. This is in addition to the `@react-native-firebase/app` plugin.

```json
{
"expo": {
"plugins": ["@react-native-firebase/app", "@react-native-firebase/auth"]
}
}
```

The `@react-native-firebase/auth` config plugin is not required for all auth providers, but it is required to use phone auth. The plugin [will set up reCAPTCHA](https://firebase.google.com/docs/auth/ios/phone-auth#set-up-recaptcha-verification) verification for you on iOS.

The recommendation is to use a [custom development client](https://docs.expo.dev/clients/getting-started/). For more info on using Expo with React Native Firebase, see our [Expo docs](/#expo).

# Sign-in

The module provides a `signInWithPhoneNumber` method which accepts a phone number. Firebase sends an SMS message to the
Expand Down
1 change: 1 addition & 0 deletions packages/auth/app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./plugin/build');
11 changes: 10 additions & 1 deletion packages/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"scripts": {
"build": "genversion --semi lib/version.js",
"build:clean": "rimraf android/build && rimraf ios/build",
"prepare": "yarn run build"
"build:plugin": "rimraf plugin/build && tsc --build plugin",
"lint:plugin": "eslint plugin/src/*",
"prepare": "yarn run build && yarn run build:plugin"
},
"repository": {
"type": "git",
Expand All @@ -21,10 +23,17 @@
"firebase",
"auth"
],
"dependencies": {
"plist": "^3.0.5",
"@expo/config-plugins": "^4.1.4"
},
"peerDependencies": {
"@react-native-firebase/app": "15.3.0"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/plist": "^3.0.2"
}
}
16 changes: 16 additions & 0 deletions packages/auth/plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ConfigPlugin, withPlugins, createRunOncePlugin } from '@expo/config-plugins';

import { withIosCaptchaUrlTypes } from './ios';

/**
* A config plugin for configuring `@react-native-firebase/auth`
*/
const withRnFirebaseAuth: ConfigPlugin = config => {
return withPlugins(config, [
// iOS
withIosCaptchaUrlTypes,
]);
};

const pak = require('@react-native-firebase/auth/package.json');
export default createRunOncePlugin(withRnFirebaseAuth, pak.name, pak.version);
3 changes: 3 additions & 0 deletions packages/auth/plugin/src/ios/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { withIosCaptchaUrlTypes } from './urlTypes';

export { withIosCaptchaUrlTypes };
93 changes: 93 additions & 0 deletions packages/auth/plugin/src/ios/urlTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import {
ConfigPlugin,
IOSConfig,
withInfoPlist,
ExportedConfigWithProps,
} from '@expo/config-plugins';
import fs from 'fs';
import path from 'path';
import plist from 'plist';

// does this for you: https://firebase.google.com/docs/auth/ios/phone-auth#enable-phone-number-sign-in-for-your-firebase-project
export const withIosCaptchaUrlTypes: ConfigPlugin = config => {
return withInfoPlist(config, config => {
if (!config.ios?.googleServicesFile) {
throw new Error(
'Path to GoogleService-Info.plist is not defined. Please specify the `expo.ios.googleServicesFile` field in app.json.',
);
}

return setUrlTypesForCaptcha({ config });
});
};

function getReversedClientId(googleServiceFilePath: string): string {
let REVERSED_CLIENT_ID: string;
try {
const googleServicePlist = fs.readFileSync(googleServiceFilePath, 'utf8');

const googleServiceJson = plist.parse(googleServicePlist) as { REVERSED_CLIENT_ID: string };
REVERSED_CLIENT_ID = googleServiceJson.REVERSED_CLIENT_ID;
} catch {
throw new Error(
'[@react-native-firebase/auth] Failed to parse your GoogleService-Info.plist. Are you sure it is a valid Info.Plist file with a REVERSE_CLIENT_ID field?',
);
}

return REVERSED_CLIENT_ID;
}

// add phone auth support by configuring recaptcha
// https://github.com/invertase/react-native-firebase/pull/6167
function addUriScheme(
config: ExportedConfigWithProps<IOSConfig.InfoPlist>,
reversedClientId: string,
): ExportedConfigWithProps<IOSConfig.InfoPlist> {
if (!config.modResults) {
config.modResults = {};
}

if (!config.modResults.CFBundleURLTypes) {
config.modResults.CFBundleURLTypes = [];
}

const hasReverseClientId = config.modResults.CFBundleURLTypes?.some(urlType =>
urlType.CFBundleURLSchemes.includes(reversedClientId),
);

if (!hasReverseClientId) {
config.modResults.CFBundleURLTypes.push({
CFBundleURLSchemes: [reversedClientId],
});
}

return config;
}

export function setUrlTypesForCaptcha({
config,
}: {
config: ExportedConfigWithProps<IOSConfig.InfoPlist>;
}) {
const googleServicesFileRelativePath = config.ios?.googleServicesFile;
if (!googleServicesFileRelativePath) {
throw new Error(
`[@react-native-firebase/auth] Your app.json file is missing ios.googleServicesFile. Please add this field.`,
);
}
const googleServiceFilePath = path.resolve(
config.modRequest.projectRoot,
googleServicesFileRelativePath,
);

if (!fs.existsSync(googleServiceFilePath)) {
throw new Error(
`[@react-native-firebase/auth] GoogleService-Info.plist doesn't exist in ${googleServiceFilePath}. Place it there or configure the path in app.json`,
);
}

const reversedClientId = getReversedClientId(googleServiceFilePath);
addUriScheme(config, reversedClientId);

return config;
}
9 changes: 9 additions & 0 deletions packages/auth/plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@tsconfig/node12/tsconfig.json",
"compilerOptions": {
"outDir": "build",
"rootDir": "src",
"declaration": true
},
"include": ["./src"]
}
26 changes: 25 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1546,7 +1546,7 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"

"@expo/config-plugins@^4.1.5":
"@expo/config-plugins@^4.1.4", "@expo/config-plugins@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-4.1.5.tgz#9d357d2cda9c095e511b51583ede8a3b76174068"
integrity sha512-RVvU40RtZt12HavuDAe+LDIq9lHj7sheOfMEHdmpJ/uTA8pgvkbc56XF6JHQD+yRr6+uhhb+JnAasGq49dsQbw==
Expand Down Expand Up @@ -3805,6 +3805,14 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==

"@types/plist@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/plist/-/plist-3.0.2.tgz#61b3727bba0f5c462fe333542534a0c3e19ccb01"
integrity sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==
dependencies:
"@types/node" "*"
xmlbuilder ">=11.0.1"

"@types/prettier@^2.1.5":
version "2.4.4"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17"
Expand Down Expand Up @@ -3943,6 +3951,9 @@
version "5.28.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.28.0.tgz#982bb226b763c48fc1859a60de33fbf939d40a0f"
integrity sha512-BtfP1vCor8cWacovzzPFOoeW4kBQxzmhxGoOpt0v1SFvG+nJ0cWaVdJk7cky1ArTcFHHKNIxyo2LLr3oNkSuXA==
dependencies:
"@typescript-eslint/types" "5.28.0"
eslint-visitor-keys "^3.3.0"

"@ungap/[email protected]":
version "1.1.2"
Expand Down Expand Up @@ -11889,6 +11900,14 @@ plist@^3.0.2, plist@^3.0.4:
base64-js "^1.5.1"
xmlbuilder "^9.0.7"

plist@^3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3"
integrity sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA==
dependencies:
base64-js "^1.5.1"
xmlbuilder "^15.1.1"

pod-install@^0.1.37:
version "0.1.37"
resolved "https://registry.yarnpkg.com/pod-install/-/pod-install-0.1.37.tgz#6ec1cf08fd6259afae6b59136879a679d85a2249"
Expand Down Expand Up @@ -14923,6 +14942,11 @@ [email protected]:
sax ">=0.6.0"
xmlbuilder "~11.0.0"

xmlbuilder@>=11.0.1, xmlbuilder@^15.1.1:
version "15.1.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==

xmlbuilder@^14.0.0:
version "14.0.0"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-14.0.0.tgz#876b5aec4f05ffd5feb97b0a871c855d16fbeb8c"
Expand Down