diff --git a/EXAMPLES.md b/EXAMPLES.md index f9e03346..aae15ecf 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -15,6 +15,7 @@ - [Log in to an organization](#log-in-to-an-organization) - [Accept user invitations](#accept-user-invitations) - [Bot Protection](#bot-protection) +- [Domain Switching](#domain-switching) ## Authentication API @@ -263,3 +264,97 @@ auth0.webAuth.authorize({ screen_hint: 'signup', // 👈🏻 }); ``` + +### Domain Switching + +To switch between two different domains for authentication in your Android and iOS applications, follow these steps: + +#### Android + +To switch between two different domains for authentication in your Android application, you need to manually update your `AndroidManifest.xml` file. This involves adding an intent filter for the activity `com.auth0.android.provider.RedirectActivity`. Unlike using a single domain where you can add the domain and scheme values within the `manifestPlaceholders` of your app's `build.gradle` file, you need to add a `` tag for each domain along with its scheme within the intent filter. + +Here is an example: + +```xml + + + + + + + + + +``` + +If you customize the scheme by removing the default value of `${applicationId}.auth0`, you will also need to pass it as the `customScheme` option parameter of the `authorize` and `clearSession` methods. + +#### iOS + +For iOS, if you are not customizing the scheme, adding `$(PRODUCT_BUNDLE_IDENTIFIER).auth0` as an entry to the `CFBundleURLSchemes` array in your `Info.plist` file should be sufficient. However, if you want to customize the scheme for the domains, you need to add the customized scheme for each domain as an entry to the `CFBundleURLSchemes` array. + +Here is an example: + +``` +CFBundleURLTypes + + + CFBundleTypeRole + None + CFBundleURLName + auth0 + CFBundleURLSchemes + + $(customScheme1) + $(customScheme2) + + + +``` + +By following these steps, you can configure your Android and iOS applications to handle authentication for multiple domains. + +#### Expo + +If using a single domain, you can simply pass an object in the format to the `react-native-auth0` plugin in your `app.json` as shown below: + +```json +"plugins": [ + "expo-router", + ["react-native-auth0", + { + "domain": "sample.auth0.com", + "customScheme": "sampleScheme" + } + ] +] +``` + +If you want to support multiple domains, you would have to pass an array of objects as shown below: + +```json +"plugins": [ + "expo-router", + ["react-native-auth0", + [{ + "domain": "sample.auth0.com", + "customScheme": "sampleScheme" + }, + { + "domain": "sample2.auth0.com", + "customScheme": "sampleScheme2" + }] + ] +] +``` + +You can skip sending the `customScheme` property if you do not want to customize it. diff --git a/README.md b/README.md index 2373a223..17cda06d 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,8 @@ To use the SDK with Expo, configure the app at build time by providing the `doma } ``` +> :info: If you want to switch between multiple domains in your app, refer [here](https://github.com/auth0/react-native-auth0/blob/master/EXAMPLES.md#domain-switching) + | API | Description | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | domain | Mandatory: Provide the Auth0 domain that can be found at the [Application Settings](https://manage.auth0.com/#/applications) | diff --git a/android/src/main/java/com/auth0/react/A0Auth0Module.java b/android/src/main/java/com/auth0/react/A0Auth0Module.java index 7fb317b2..d98ca65d 100644 --- a/android/src/main/java/com/auth0/react/A0Auth0Module.java +++ b/android/src/main/java/com/auth0/react/A0Auth0Module.java @@ -2,10 +2,8 @@ import android.app.Activity; import android.content.Intent; -import android.content.ActivityNotFoundException; -import android.net.Uri; + import androidx.annotation.NonNull; -import android.util.Base64; import com.auth0.android.Auth0; import com.auth0.android.authentication.AuthenticationAPIClient; @@ -16,27 +14,21 @@ import com.auth0.android.provider.WebAuthProvider; import com.auth0.android.result.Credentials; import com.facebook.react.bridge.ActivityEventListener; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.Map; -import static android.app.Activity.RESULT_OK; - public class A0Auth0Module extends ReactContextBaseJavaModule implements ActivityEventListener { - private static final String ERROR_CODE = "a0.invalid_state.credential_manager_exception"; + private static final String CREDENTIAL_MANAGER_ERROR_CODE = "a0.invalid_state.credential_manager_exception"; + private static final String INVALID_DOMAIN_URL_ERROR_CODE = "a0.invalid_domain_url"; private static final int LOCAL_AUTH_REQUEST_CODE = 150; public static final int UNKNOWN_ERROR_RESULT_CODE = 1405; @@ -52,7 +44,7 @@ public A0Auth0Module(ReactApplicationContext reactContext) { } @ReactMethod - public void initializeAuth0(String clientId, String domain) { + public void initializeAuth0WithConfiguration(String clientId, String domain) { this.auth0 = new Auth0(clientId, domain); AuthenticationAPIClient authenticationAPIClient = new AuthenticationAPIClient(auth0); this.secureCredentialsManager = new SecureCredentialsManager( @@ -63,13 +55,25 @@ public void initializeAuth0(String clientId, String domain) { } @ReactMethod - public void hasValidAuth0Instance(Promise promise) { - promise.resolve(this.auth0 != null && this.secureCredentialsManager != null); + public void hasValidAuth0InstanceWithConfiguration(String clientId, String domain, Promise promise) { + if(this.auth0 == null) { + promise.resolve(false); + return; + } + String currentDomain; + try { + URL domainUrl = new URL(this.auth0.getDomainUrl()); + currentDomain = domainUrl.getHost(); + } catch (MalformedURLException e) { + promise.reject(INVALID_DOMAIN_URL_ERROR_CODE, "Invalid domain URL", e); + return; + } + promise.resolve(this.auth0.getClientId().equals(clientId) && currentDomain.equals(domain)); } @ReactMethod public void getCredentials(String scope, double minTtl, ReadableMap parameters, boolean forceRefresh, Promise promise) { - Map cleanedParameters = new HashMap<>(); + Map cleanedParameters = new HashMap<>(); for (Map.Entry entry : parameters.toHashMap().entrySet()) { if (entry.getValue() != null) { cleanedParameters.put(entry.getKey(), entry.getValue().toString()); @@ -85,7 +89,7 @@ public void onSuccess(Credentials credentials) { @Override public void onFailure(@NonNull CredentialsManagerException e) { - promise.reject(ERROR_CODE, e.getMessage(), e); + promise.reject(CREDENTIAL_MANAGER_ERROR_CODE, e.getMessage(), e); } }); } @@ -96,7 +100,7 @@ public void saveCredentials(ReadableMap credentials, Promise promise) { this.secureCredentialsManager.saveCredentials(CredentialsParser.fromMap(credentials)); promise.resolve(true); } catch (CredentialsManagerException e) { - promise.reject(ERROR_CODE, e.getMessage(), e); + promise.reject(CREDENTIAL_MANAGER_ERROR_CODE, e.getMessage(), e); } } @@ -104,15 +108,15 @@ public void saveCredentials(ReadableMap credentials, Promise promise) { public void enableLocalAuthentication(String title, String description, Promise promise) { Activity activity = reactContext.getCurrentActivity(); if (activity == null) { - promise.reject(ERROR_CODE, "No current activity present"); + promise.reject(CREDENTIAL_MANAGER_ERROR_CODE, "No current activity present"); return; } activity.runOnUiThread(() -> { try { A0Auth0Module.this.secureCredentialsManager.requireAuthentication(activity, LOCAL_AUTH_REQUEST_CODE, title, description); promise.resolve(true); - } catch (CredentialsManagerException e){ - promise.reject(ERROR_CODE, e.getMessage(), e); + } catch (CredentialsManagerException e) { + promise.reject(CREDENTIAL_MANAGER_ERROR_CODE, e.getMessage(), e); } }); } @@ -144,7 +148,7 @@ public String getName() { @ReactMethod public void webAuth(String scheme, String redirectUri, String state, String nonce, String audience, String scope, String connection, int maxAge, String organization, String invitationUrl, int leeway, boolean ephemeralSession, int safariViewControllerPresentationStyle, ReadableMap additionalParameters, Promise promise) { this.webAuthPromise = promise; - Map cleanedParameters = new HashMap<>(); + Map cleanedParameters = new HashMap<>(); for (Map.Entry entry : additionalParameters.toHashMap().entrySet()) { if (entry.getValue() != null) { cleanedParameters.put(entry.getKey(), entry.getValue().toString()); @@ -152,61 +156,61 @@ public void webAuth(String scheme, String redirectUri, String state, String nonc } WebAuthProvider.Builder builder = WebAuthProvider.login(this.auth0) .withScheme(scheme); - if(state != null) { + if (state != null) { builder.withState(state); } - if(nonce != null) { + if (nonce != null) { builder.withNonce(nonce); } - if(audience != null) { + if (audience != null) { builder.withAudience(audience); } - if(scope != null) { + if (scope != null) { builder.withScope(scope); } - if(connection != null) { + if (connection != null) { builder.withConnection(connection); } - if(maxAge != 0) { + if (maxAge != 0) { builder.withMaxAge(maxAge); } - if(organization != null) { + if (organization != null) { builder.withOrganization(organization); } - if(invitationUrl != null) { + if (invitationUrl != null) { builder.withInvitationUrl(invitationUrl); } - if(leeway != 0) { + if (leeway != 0) { builder.withIdTokenVerificationLeeway(leeway); } - if(redirectUri != null) { + if (redirectUri != null) { builder.withRedirectUri(redirectUri); } builder.withParameters(cleanedParameters); builder.start(reactContext.getCurrentActivity(), new com.auth0.android.callback.Callback() { - @Override - public void onSuccess(Credentials result) { - ReadableMap map = CredentialsParser.toMap(result); - promise.resolve(map); - webAuthPromise = null; - } + @Override + public void onSuccess(Credentials result) { + ReadableMap map = CredentialsParser.toMap(result); + promise.resolve(map); + webAuthPromise = null; + } - @Override - public void onFailure(@NonNull AuthenticationException error) { - handleError(error, promise); - webAuthPromise = null; - } - }); + @Override + public void onFailure(@NonNull AuthenticationException error) { + handleError(error, promise); + webAuthPromise = null; + } + }); } @ReactMethod public void webAuthLogout(String scheme, boolean federated, String redirectUri, Promise promise) { WebAuthProvider.LogoutBuilder builder = WebAuthProvider.logout(this.auth0) .withScheme(scheme); - if(federated) { + if (federated) { builder.withFederated(); } - if(redirectUri != null) { + if (redirectUri != null) { builder.withReturnToUrl(redirectUri); } builder.start(reactContext.getCurrentActivity(), new com.auth0.android.callback.Callback() { @@ -223,19 +227,19 @@ public void onFailure(AuthenticationException e) { } private void handleError(AuthenticationException error, Promise promise) { - if(error.isBrowserAppNotAvailable()) { + if (error.isBrowserAppNotAvailable()) { promise.reject("a0.browser_not_available", "No Browser application is installed.", error); return; } - if(error.isCanceled()) { + if (error.isCanceled()) { promise.reject("a0.session.user_cancelled", "User cancelled the Auth", error); return; } - if(error.isNetworkError()) { + if (error.isNetworkError()) { promise.reject("a0.network_error", "Network error", error); return; } - if(error.isIdTokenValidationError()) { + if (error.isIdTokenValidationError()) { promise.reject("a0.session.invalid_idtoken", "Error validating ID Token", error); return; } @@ -245,14 +249,14 @@ private void handleError(AuthenticationException error, Promise promise) { @Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { - if(requestCode == LOCAL_AUTH_REQUEST_CODE) { + if (requestCode == LOCAL_AUTH_REQUEST_CODE) { secureCredentialsManager.checkAuthenticationResult(requestCode, resultCode); } } @Override public void onNewIntent(Intent intent) { - if(webAuthPromise != null) { + if (webAuthPromise != null) { webAuthPromise.reject("a0.session.browser_terminated", "The browser window was closed by a new instance of the application"); webAuthPromise = null; } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index a9d55982..281bffd9 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -96,7 +96,6 @@ android { namespace "com.auth0example" defaultConfig { applicationId "com.auth0example" - manifestPlaceholders = [auth0Domain: "brucke.auth0.com", auth0Scheme: "${applicationId}.auth0"] minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 4122f36a..f09c63d4 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,25 +1,44 @@ - + + - - - + - - - - - - - - + android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" + android:launchMode="singleTask" + android:windowSoftInputMode="adjustResize" + android:exported="true"> + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index fc40317b..562abbf0 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -338,6 +338,8 @@ PODS: - React-jsinspector (0.71.10) - React-logger (0.71.10): - glog + - react-native-safe-area-context (4.10.8): + - React-Core - React-perflogger (0.71.10) - React-RCTActionSheet (0.71.10): - React-Core/RCTActionSheetHeaders (= 0.71.10) @@ -422,6 +424,10 @@ PODS: - React-jsi (= 0.71.10) - React-logger (= 0.71.10) - React-perflogger (= 0.71.10) + - RNScreens (3.32.0): + - RCT-Folly (= 2021.07.22.00) + - React-Core + - React-RCTImage - SimpleKeychain (1.1.0) - SocketRocket (0.6.1) - Yoga (1.14.0) @@ -475,6 +481,7 @@ DEPENDENCIES: - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) @@ -488,6 +495,7 @@ DEPENDENCIES: - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - RNScreens (from `../node_modules/react-native-screens`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -554,6 +562,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/jsinspector" React-logger: :path: "../node_modules/react-native/ReactCommon/logger" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" React-perflogger: :path: "../node_modules/react-native/ReactCommon/reactperflogger" React-RCTActionSheet: @@ -580,6 +590,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" ReactCommon: :path: "../node_modules/react-native/ReactCommon" + RNScreens: + :path: "../node_modules/react-native-screens" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" @@ -620,6 +632,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 4bb480a183a354e4dbfb1012936b1a2bb9357de7 React-jsinspector: cdc854f8b13abd202afa54bc12578e5afb9cfae1 React-logger: ef2269b3afa6ba868da90496c3e17a4ec4f4cee0 + react-native-safe-area-context: b7daa1a8df36095a032dff095a1ea8963cb48371 React-perflogger: 217095464d5c4bb70df0742fa86bf2a363693468 React-RCTActionSheet: 8deae9b85a4cbc6a2243618ea62a374880a2c614 React-RCTAnimation: 59c62353a8b59ce206044786c5d30e4754bffa64 @@ -633,10 +646,9 @@ SPEC CHECKSUMS: React-RCTVibration: d13cc2d63286c633393d3a7f6f607cc2a09ec011 React-runtimeexecutor: a9a1cd79996c9a0846e3232ecb25c64e1cc0172e ReactCommon: 65718685d4095d06b4b1af8042e12f1df2925c31 + RNScreens: 0bd9eec783bed1032e02a4db9976dae1664a5c7b SimpleKeychain: f8707c8e97b38c6a6e687b17732afc9bcef06439 - SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: e7ea9e590e27460d28911403b894722354d73479 - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 8b76cdfa2c2f558cb3fb9288d07f13c3d579c8c9 diff --git a/example/package-lock.json b/example/package-lock.json index 43b40e03..6e1c0a9f 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -9,8 +9,12 @@ "version": "0.0.1", "hasInstallScript": true, "dependencies": { + "@react-navigation/native": "^6.1.18", + "@react-navigation/native-stack": "^6.10.1", "react": "18.2.0", - "react-native": "0.71.10" + "react-native": "0.71.10", + "react-native-safe-area-context": "^4.10.8", + "react-native-screens": "^3.32.0" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -2722,6 +2726,99 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==", "license": "MIT" }, + "node_modules/@react-navigation/core": { + "version": "6.4.17", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.17.tgz", + "integrity": "sha512-Nd76EpomzChWAosGqWOYE3ItayhDzIEzzZsT7PfGcRFDgW5miHV2t4MZcq9YIK4tzxZjVVpYbIynOOQQd1e0Cg==", + "dependencies": { + "@react-navigation/routers": "^6.1.9", + "escape-string-regexp": "^4.0.0", + "nanoid": "^3.1.23", + "query-string": "^7.1.3", + "react-is": "^16.13.0", + "use-latest-callback": "^0.2.1" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@react-navigation/core/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/@react-navigation/elements": { + "version": "1.3.31", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.31.tgz", + "integrity": "sha512-bUzP4Awlljx5RKEExw8WYtif8EuQni2glDaieYROKTnaxsu9kEIA515sXQgUDZU4Ob12VoL7+z70uO3qrlfXcQ==", + "peerDependencies": { + "@react-navigation/native": "^6.0.0", + "react": "*", + "react-native": "*", + "react-native-safe-area-context": ">= 3.0.0" + } + }, + "node_modules/@react-navigation/native": { + "version": "6.1.18", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.18.tgz", + "integrity": "sha512-mIT9MiL/vMm4eirLcmw2h6h/Nm5FICtnYSdohq4vTLA2FF/6PNhByM7s8ffqoVfE5L0uAa6Xda1B7oddolUiGg==", + "dependencies": { + "@react-navigation/core": "^6.4.17", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.1.23" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/@react-navigation/native-stack": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.10.1.tgz", + "integrity": "sha512-MDTHtelO2EhY1sEbz4YMNw+1YoE0sWXSHLUYireQZFHUXKDfYiWYbxXg2Q08Ool0KEvnZjP0hh0Wm6/ZnvDCtw==", + "dependencies": { + "@react-navigation/elements": "^1.3.31", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "@react-navigation/native": "^6.0.0", + "react": "*", + "react-native": "*", + "react-native-safe-area-context": ">= 3.0.0", + "react-native-screens": ">= 3.0.0" + } + }, + "node_modules/@react-navigation/native/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-navigation/routers": { + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.9.tgz", + "integrity": "sha512-lTM8gSFHSfkJvQkxacGM6VJtBt61ip2XO54aNfswD+KMw6eeZ4oehl7m0me3CR9hnDE4+60iAZR8sAhvCiI3NA==", + "dependencies": { + "nanoid": "^3.1.23" + } + }, "node_modules/@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -3911,6 +4008,14 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -6082,6 +6187,23 @@ "once": "^1.3.1" } }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6113,6 +6235,17 @@ "ws": "^7" } }, + "node_modules/react-freeze": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", + "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0.0" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -6187,6 +6320,28 @@ "integrity": "sha512-1dVk9NwhoyKHCSxcrM6vY6cxmojeATsBobDicX0ZKr7DgUF2cBQRTKsimQFvzH8XhOVXyH8p4HyDSZNIFI8OlQ==", "license": "MIT" }, + "node_modules/react-native-safe-area-context": { + "version": "4.10.8", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.10.8.tgz", + "integrity": "sha512-Jx1lovhvIdYygg0UsMCBUJN0Wvj9GlA5bbcBLzjZf93uJpNHzaiHC4hR280+sNVK1+/pMHEyEkXVHDZE5JWn0w==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-screens": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.32.0.tgz", + "integrity": "sha512-wybqZAHX7v8ipOXhh90CqGLkBHw5JYqKNRBX7R/b0c2WQisTOgu0M0yGwBMM6LyXRBT+4k3NTGHdDbpJVpq0yQ==", + "dependencies": { + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native/node_modules/metro-runtime": { "version": "0.73.9", "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.73.9.tgz", @@ -6753,6 +6908,14 @@ "node": ">= 0.8" } }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -7127,6 +7290,11 @@ "makeerror": "1.0.12" } }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==" + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/example/package.json b/example/package.json index 6e73c5dc..c4121a24 100644 --- a/example/package.json +++ b/example/package.json @@ -10,14 +10,18 @@ "postinstall": "npm run pods" }, "dependencies": { + "@react-navigation/native": "^6.1.18", + "@react-navigation/native-stack": "^6.10.1", "react": "18.2.0", - "react-native": "0.71.10" + "react-native": "0.71.10", + "react-native-safe-area-context": "^4.10.8", + "react-native-screens": "^3.32.0" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", - "metro-react-native-babel-preset": "0.73.9", - "babel-plugin-module-resolver": "^5.0.0" + "babel-plugin-module-resolver": "^5.0.0", + "metro-react-native-babel-preset": "0.73.9" } } diff --git a/example/src/App.tsx b/example/src/App.tsx index 0f354c9e..8a5d765a 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -10,8 +10,12 @@ import React from 'react'; import { Alert, Button, StyleSheet, Text, View } from 'react-native'; import { useAuth0, Auth0Provider } from 'react-native-auth0'; import config from './auth0-configuration'; +import { NavigationProp, NavigationContainer } from '@react-navigation/native'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; -const Home = () => { +const Stack = createNativeStackNavigator(); + +const Home = ({ navigation }: { navigation: NavigationProp }) => { const { authorize, clearSession, user, getCredentials, error } = useAuth0(); const onLogin = async () => { @@ -35,19 +39,74 @@ const Home = () => { onPress={loggedIn ? onLogout : onLogin} title={loggedIn ? 'Log Out' : 'Log In'} /> +