diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f709ec67..115cab28 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -14,12 +14,15 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 cache: 'yarn' - name: Install dependencies run: yarn install --frozen-lockfile + - name: Build Plugin + run: yarn run build + - name: Lint run: yarn run lint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0111abc..1d1449f3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,6 +28,9 @@ jobs: - name: Install dependencies run: yarn install --frozen-lockfile + - name: Build Plugin + run: yarn run build + - name: Unit Tests run: yarn test diff --git a/.gitignore b/.gitignore index 6edaa449..9c679a54 100644 --- a/.gitignore +++ b/.gitignore @@ -43,9 +43,20 @@ node_modules/ npm-debug.log yarn-error.log +# TypeScript +# +*.tsbuildinfo + # BUCK buck-out/ \.buckd/ *.keystore Example/yarn.lock + +examples/expo-cng/.expo +examples/expo-cng/ios +examples/expo-cng/android +examples/expo-cng/*.tsbuildinfo + + diff --git a/app.json b/app.json new file mode 100644 index 00000000..797df9e5 --- /dev/null +++ b/app.json @@ -0,0 +1,5 @@ +{ + "ios": { + "bundleIdentifier": "com.anonymous.rnaa" + } +} diff --git a/docs/docs/introduction.md b/docs/docs/introduction.md index 10cbbaa1..095d17cd 100644 --- a/docs/docs/introduction.md +++ b/docs/docs/introduction.md @@ -39,7 +39,32 @@ try { } ``` -## Setup +## Expo Setup (SDK 53+) + +If you're using **Expo with Continuous Native Generation (CNG)**, you can use our config plugin for automatic setup: + +```json +{ + "expo": { + "plugins": [ + [ + "react-native-app-auth", + { + "redirectUrls": ["com.yourapp.scheme://oauth"] + } + ] + ] + } +} +``` + +Then run `expo prebuild` to generate your iOS and Android projects with the correct OAuth URL scheme configuration. + +**๐Ÿ“– [Complete Expo Setup Guide โ†’](./usage/expo-setup)** + +## Manual Setup + +> **๐Ÿ’ก Using Expo?** Check out the [Expo Setup Guide](./usage/expo-setup) for a simpler configuration process. ### iOS Setup @@ -273,6 +298,8 @@ If you want to support universal links, add the following to `AppDelegate.m` und ### Android Setup +> **๐Ÿ’ก Using Expo?** Check out the [Expo Setup Guide](./usage/expo-setup) for automatic configuration. + To setup the Android project, you need to add redirect scheme manifest placeholder: To [capture the authorization redirect](https://github.com/openid/AppAuth-android#capturing-the-authorization-redirect), diff --git a/docs/docs/usage/authorization.md b/docs/docs/usage/authorization.md index d7c11a24..506cca41 100644 --- a/docs/docs/usage/authorization.md +++ b/docs/docs/usage/authorization.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 4 --- # Authorization diff --git a/docs/docs/usage/config.md b/docs/docs/usage/config.md index 48ff6183..47570aef 100644 --- a/docs/docs/usage/config.md +++ b/docs/docs/usage/config.md @@ -1,5 +1,5 @@ --- -sidebar_position: 1 +sidebar_position: 3 --- # Configuration diff --git a/docs/docs/usage/errors.md b/docs/docs/usage/errors.md index 21c7b31f..3f19f2c0 100644 --- a/docs/docs/usage/errors.md +++ b/docs/docs/usage/errors.md @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 9 --- # Error Messages diff --git a/docs/docs/usage/expo-setup.md b/docs/docs/usage/expo-setup.md new file mode 100644 index 00000000..7f921652 --- /dev/null +++ b/docs/docs/usage/expo-setup.md @@ -0,0 +1,183 @@ +--- +sidebar_position: 1 +--- + +# Expo Setup + +React Native App Auth provides seamless integration with Expo through our config plugin, supporting **Expo SDK 53+** with Continuous Native Generation (CNG). + +## Prerequisites + +- Expo SDK 53 or later +- CNG workflow (not Expo Go) +- `expo prebuild` capability + +## Quick Start + +### 1. Install the Library + +```bash +npm install react-native-app-auth +# or +yarn add react-native-app-auth +``` + +### 2. Configure the Plugin + +Add the plugin to your `app.json` or `app.config.js`: + +```json +{ + "expo": { + "plugins": [ + [ + "react-native-app-auth", + { + "redirectUrls": ["com.yourapp.scheme://oauth"] + } + ] + ] + } +} +``` + +**Configuration Options:** + +- `redirectUrls` (required): Array of OAuth redirect URLs for your app + - The URL scheme (before `://`) will be automatically configured for both iOS and Android + - Example: `"com.myapp://oauth"` โ†’ scheme is `com.myapp` + +### 3. Generate Native Projects + +Run prebuild to generate iOS and Android projects with OAuth configuration: + +```bash +npx expo prebuild --clean +``` + +This automatically: +- **iOS**: Adds URL scheme to `Info.plist` and configures bridging headers +- **Android**: Sets up manifest placeholders in `build.gradle` + +### 4. Use the Library + +```typescript +import { authorize, AuthConfiguration } from 'react-native-app-auth'; + +const config: AuthConfiguration = { + issuer: 'https://your-oauth-provider.com', + clientId: 'your-client-id', + redirectUrl: 'com.yourapp.scheme://oauth', // Must match app.json + scopes: ['openid', 'profile', 'email'], +}; + +// Perform authentication +try { + const result = await authorize(config); + console.log('Access token:', result.accessToken); +} catch (error) { + console.error('Auth error:', error); +} +``` + +## Validation + +After running `expo prebuild`, verify the configuration was applied correctly: + +### iOS Configuration + +Check that your URL scheme was added to `ios/YourApp/Info.plist`: + +```xml +CFBundleURLTypes + + + CFBundleURLName + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleURLSchemes + + com.yourapp.scheme + + + +``` + +### Android Configuration + +Check that the manifest placeholder was added to `android/app/build.gradle`: + +```gradle +android { + defaultConfig { + manifestPlaceholders = [ + appAuthRedirectScheme: 'com.yourapp.scheme', + ] + } +} +``` + +## TypeScript Support + +The plugin is built with TypeScript and provides full type safety. Import types as needed: + +```typescript +import { + AuthConfiguration, + AuthorizeResult, + RefreshResult +} from 'react-native-app-auth'; +``` + +## Example App + +Check out our working example in [`examples/expo-cng/`](https://github.com/FormidableLabs/react-native-app-auth/tree/main/examples/expo-cng) which demonstrates: + +- Complete TypeScript implementation +- Expo config plugin setup +- OAuth flow with Duende IdentityServer demo +- Native project generation validation + +## Troubleshooting + +### Plugin Not Found + +If you see "Package 'react-native-app-auth' does not contain a valid config plugin": + +1. Ensure you're using the latest version of the library +2. Clear your cache: `npx expo install --fix` +3. Try `npx expo prebuild --clean` to regenerate projects + +### URL Scheme Conflicts + +If you have React Navigation deep linking, ensure your OAuth scheme is different: + +```json +{ + "expo": { + "plugins": [ + [ + "react-native-app-auth", + { "redirectUrls": ["com.myapp.auth://oauth"] } + ] + ] + } +} +``` + + +## Migration from Manual Setup + +If you're migrating from manual iOS/Android setup: + +1. Remove manual URL scheme configurations from `Info.plist` and `build.gradle` +2. Remove manual AppDelegate modifications (the plugin handles this automatically for Expo SDK 53+) +3. Add the plugin configuration to `app.json` +4. Run `npx expo prebuild --clean` + +## Limitations + +- **Expo SDK 53+ only**: Earlier versions require [manual setup](../#manual-setup) +- **CNG workflow only**: Expo Go is not supported (OAuth requires native configuration) +- **First-party providers**: Some OAuth providers may require additional native configuration + +For advanced use cases or non-Expo projects, see the [Manual Setup Guide](../#manual-setup). \ No newline at end of file diff --git a/docs/docs/usage/logout.md b/docs/docs/usage/logout.md index 726ea857..880c518f 100644 --- a/docs/docs/usage/logout.md +++ b/docs/docs/usage/logout.md @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 8 --- # Logout diff --git a/docs/docs/usage/manual-setup.md b/docs/docs/usage/manual-setup.md new file mode 100644 index 00000000..6574a1f4 --- /dev/null +++ b/docs/docs/usage/manual-setup.md @@ -0,0 +1,294 @@ +--- +sidebar_position: 2 +--- + +# Manual Setup + +> **๐Ÿ’ก Using Expo?** Check out the [Expo Setup Guide](./expo-setup) for a simpler configuration process. + +For React Native projects that don't use Expo, or for advanced configurations, you'll need to manually configure iOS and Android projects. + +## iOS Setup + +To setup the iOS project, you need to perform three steps: + +1. [Install native dependencies](#install-native-dependencies) +2. [Register redirect URL scheme](#register-redirect-url-scheme) +3. [Define openURL callback in AppDelegate](#define-openurl-callback-in-appdelegate) + +### Install native dependencies + +This library depends on the native [AppAuth-ios](https://github.com/openid/AppAuth-iOS) project. To +keep the React Native library agnostic of your dependency management method, the native libraries +are not distributed as part of the bridge. + +AppAuth supports three options for dependency management. + +1. **CocoaPods** + + ```sh + cd ios + pod install + ``` + +2. **Carthage** + + With [Carthage](https://github.com/Carthage/Carthage), add the following line to your `Cartfile`: + + github "openid/AppAuth-iOS" "master" + + Then run `carthage update --platform iOS --use-xcframeworks`. + + Drag and drop `AppAuth.xcframework` from `ios/Carthage/Build` under `Frameworks` in `Xcode`. + + Add a copy files build step for `AppAuth.xcframework`: open Build Phases on Xcode, add a new "Copy Files" phase, choose "Frameworks" as destination, add `AppAuth.xcframework` and ensure "Code Sign on Copy" is checked. + +3. **Static Library** + + You can also use [AppAuth-iOS](https://github.com/openid/AppAuth-iOS) as a static library. This + requires linking the library and your project and including the headers. Suggested configuration: + + 1. Create an XCode Workspace. + 2. Add `AppAuth.xcodeproj` to your Workspace. + 3. Include libAppAuth as a linked library for your target (in the "General -> Linked Framework and + Libraries" section of your target). + 4. Add `AppAuth-iOS/Source` to your search paths of your target ("Build Settings -> "Header Search + Paths"). + +### Register redirect URL scheme + +If you intend to support iOS 10 and older, you need to define the supported redirect URL schemes in +your `Info.plist` as follows: + +```xml +CFBundleURLTypes + + + CFBundleURLName + com.your.app.identifier + CFBundleURLSchemes + + io.identityserver.demo + + + +``` + +- `CFBundleURLName` is any globally unique string. A common practice is to use your app identifier. +- `CFBundleURLSchemes` is an array of URL schemes your app needs to handle. The scheme is the + beginning of your OAuth Redirect URL, up to the scheme separator (`:`) character. E.g. if your redirect uri + is `com.myapp://oauth`, then the url scheme will is `com.myapp`. + +### Define openURL callback in AppDelegate + +You need to retain the auth session, in order to continue the +authorization flow from the redirect. Follow these steps: + +#### For react-native >= 0.77 + +As of `react-native@0.77`, the `AppDelegate` template is now written in Swift. + +In order to bridge to the existing Objective-C code that this package utilizes, you need to create a bridging header file. To do so: + +1. Create a new file in your project called `AppDelegate+RNAppAuth.h`. (It can be called anything, but it must end with `.h`) +2. Add the following code to the file: + +``` +#import "RNAppAuthAuthorizationFlowManager.h" +``` + +3. Ensure that your XCode "Build Settings" has the following `Objective-C Bridging Header` path set to the file you just created. For example, it make look something like: `$(SRCROOT)/AppDelegate+RNAppAuth.h` + +4. Add the following code to `AppDelegate.swift` to support React Navigation deep linking and overriding browser behavior in the authorization process + +```swift +@main +class AppDelegate: UIResponder, UIApplicationDelegate, + RNAppAuthAuthorizationFlowManager { + //... existing code... + // Required by RNAppAuthAuthorizationFlowManager protocol + public weak var authorizationFlowManagerDelegate: + RNAppAuthAuthorizationFlowManagerDelegate? + //... existing code... + + // Handle OAuth redirect URL + func application( + _ app: UIApplication, + open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] = [:] + ) -> Bool { + if let authorizationFlowManagerDelegate = self + .authorizationFlowManagerDelegate + { + if authorizationFlowManagerDelegate.resumeExternalUserAgentFlow(with: url) + { + return true + } + } + return false + } +} +``` + +5. Add the following code to `AppDelegate.swift` to support universal links: + +```swift + + + func application( + _ application: UIApplication, + continue userActivity: NSUserActivity, + restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void + ) -> Bool { + + // Handle Universal-Linkโ€“style OAuth redirects first + if userActivity.activityType == NSUserActivityTypeBrowsingWeb, + let delegate = authorizationFlowManagerDelegate, + delegate.resumeExternalUserAgentFlow(with: userActivity.webpageURL) + { + return true + } + + // Fall back to React Native's own Linking logic + return RCTLinkingManager.application( + application, + continue: userActivity, + restorationHandler: restorationHandler + ) + } +``` + +#### For react-native >= 0.68 + +```diff ++ #import ++ #import "RNAppAuthAuthorizationFlowManager.h" + +- @interface AppDelegate : RCTAppDelegate ++ @interface AppDelegate : RCTAppDelegate + ++ @property(nonatomic, weak) id authorizationFlowManagerDelegate; +``` + +Add the following code to `AppDelegate.mm` to support React Navigation deep linking and overriding browser behavior in the authorization process + +```diff ++ - (BOOL) application: (UIApplication *)application ++ openURL: (NSURL *)url ++ options: (NSDictionary *) options ++ { ++ if ([self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]) { ++ return YES; ++ } ++ return [RCTLinkingManager application:application openURL:url options:options]; ++ } +``` + +If you want to support universal links, add the following to `AppDelegate.mm` under `continueUserActivity` + +```diff ++ - (BOOL) application: (UIApplication *) application ++ continueUserActivity: (nonnull NSUserActivity *)userActivity ++ restorationHandler: (nonnull void (^)(NSArray> * _Nullable))restorationHandler ++ { ++ if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { ++ if (self.authorizationFlowManagerDelegate) { ++ BOOL resumableAuth = [self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:userActivity.webpageURL]; ++ if (resumableAuth) { ++ return YES; ++ } ++ } ++ } ++ return [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; ++ } +``` + +#### For react-native < 0.68 + +```diff ++ #import "RNAppAuthAuthorizationFlowManager.h" + +- @interface AppDelegate : UIResponder ++ @interface AppDelegate : UIResponder + ++ @property(nonatomic, weak)idauthorizationFlowManagerDelegate; +``` + +Add the following code to `AppDelegate.m` (to support iOS 10, React Navigation deep linking and overriding browser behavior in the authorization process) + +```diff ++ - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *) options { ++ if ([self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]) { ++ return YES; ++ } ++ return [RCTLinkingManager application:app openURL:url options:options]; ++ } +``` + +If you want to support universal links, add the following to `AppDelegate.m` under `continueUserActivity` + +```diff ++ if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { ++ if (self.authorizationFlowManagerDelegate) { ++ BOOL resumableAuth = [self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:userActivity.webpageURL]; ++ if (resumableAuth) { ++ return YES; ++ } ++ } ++ } +``` + +## Android Setup + +> **๐Ÿ’ก Using Expo?** Check out the [Expo Setup Guide](./expo-setup) for automatic configuration. + +To setup the Android project, you need to add redirect scheme manifest placeholder: + +To [capture the authorization redirect](https://github.com/openid/AppAuth-android#capturing-the-authorization-redirect), +add the following property to the defaultConfig in `android/app/build.gradle`: + +``` +android { + defaultConfig { + manifestPlaceholders = [ + appAuthRedirectScheme: 'io.identityserver.demo' + ] + } +} +``` + +The scheme is the beginning of your OAuth Redirect URL, up to the scheme separator (`:`) character. E.g. if your redirect uri +is `com.myapp://oauth`, then the url scheme will is `com.myapp`. The scheme must be in lowercase. + +NOTE: When integrating with [React Navigation deep linking](https://reactnavigation.org/docs/deep-linking/#set-up-with-bare-react-native-projects), be sure to make this scheme (and the scheme in the config's redirectUrl) unique from the scheme defined in the deep linking intent-filter. E.g. if the scheme in your intent-filter is set to `com.myapp`, then update the above scheme/redirectUrl to be `com.myapp.auth` [as seen here](https://github.com/FormidableLabs/react-native-app-auth/issues/494#issuecomment-797394994). + +### App Links + +If your OAuth Redirect URL is an [App Links](https://developer.android.com/training/app-links), you need to add the following code to your `AndroidManifest.xml`: + +```xml + + + + + + + + +``` + +Replace `android:host` with the domain of your redirect uri. + +You need to add the `manifestPlaceholders` as described in the section above: + +``` +android { + defaultConfig { + manifestPlaceholders = [ + appAuthRedirectScheme: 'example.domain' + ] + } +} +``` \ No newline at end of file diff --git a/docs/docs/usage/prefetch.md b/docs/docs/usage/prefetch.md index e9e0885b..e16b8c4f 100644 --- a/docs/docs/usage/prefetch.md +++ b/docs/docs/usage/prefetch.md @@ -1,5 +1,5 @@ --- -sidebar_position: 8 +sidebar_position: 10 --- # Android Prefetch diff --git a/docs/docs/usage/refresh.md b/docs/docs/usage/refresh.md index 41a827ba..923de75c 100644 --- a/docs/docs/usage/refresh.md +++ b/docs/docs/usage/refresh.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 5 --- # Refresh Token diff --git a/docs/docs/usage/register.md b/docs/docs/usage/register.md index 01371df2..236ab130 100644 --- a/docs/docs/usage/register.md +++ b/docs/docs/usage/register.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 6 --- # Registration diff --git a/docs/docs/usage/revoke.md b/docs/docs/usage/revoke.md index 4114ba78..6a4bba7d 100644 --- a/docs/docs/usage/revoke.md +++ b/docs/docs/usage/revoke.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 7 --- # Revoke Token diff --git a/examples/demo/ios/Example.xcodeproj/project.pbxproj b/examples/demo/ios/Example.xcodeproj/project.pbxproj index 485786b3..bab5f5ac 100644 --- a/examples/demo/ios/Example.xcodeproj/project.pbxproj +++ b/examples/demo/ios/Example.xcodeproj/project.pbxproj @@ -193,14 +193,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; @@ -236,14 +232,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n"; @@ -392,7 +384,10 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; @@ -461,7 +456,10 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; diff --git a/examples/demo/ios/Podfile.lock b/examples/demo/ios/Podfile.lock index 98e6210b..08784a6e 100644 --- a/examples/demo/ios/Podfile.lock +++ b/examples/demo/ios/Podfile.lock @@ -1338,7 +1338,7 @@ PODS: - React-jsiexecutor - React-RCTFBReactNativeSpec - ReactCommon/turbomodule/core - - react-native-app-auth (8.0.2): + - react-native-app-auth (8.0.3): - AppAuth (>= 1.7.6) - React-Core - React-NativeModulesApple (0.79.2): @@ -1931,7 +1931,7 @@ SPEC CHECKSUMS: React-logger: 368570a253f00879a1e4fea24ed4047e72e7bbf3 React-Mapbuffer: c04fcda1c6281fc0a6824c7dcc1633dd217ac1ec React-microtasksnativemodule: ca2804a25fdcefffa0aa942aa23ab53b99614a34 - react-native-app-auth: 390986b663497d92de5c00d77b6e2c947d52995e + react-native-app-auth: 149f01d2c824758453c9e7815217ded451974683 React-NativeModulesApple: 452b86b29fae99ed0a4015dca3ad9cd222f88abf React-oscompat: ef5df1c734f19b8003e149317d041b8ce1f7d29c React-perflogger: 6fd2f6811533e9c19a61e855c3033eecbf4ad2a0 diff --git a/examples/expo-cng/.gitignore b/examples/expo-cng/.gitignore new file mode 100644 index 00000000..b1bc7e4d --- /dev/null +++ b/examples/expo-cng/.gitignore @@ -0,0 +1,39 @@ +# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files + +# dependencies +node_modules/ + +/android +/ios +# Expo +.expo/ +dist/ +web-build/ +expo-env.d.ts + +# Native +.kotlin/ +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# local env files +.env*.local + +# typescript +*.tsbuildinfo diff --git a/examples/expo-cng/App.tsx b/examples/expo-cng/App.tsx new file mode 100644 index 00000000..c702a19d --- /dev/null +++ b/examples/expo-cng/App.tsx @@ -0,0 +1,113 @@ +import React, { useState } from 'react'; +import { StatusBar } from 'expo-status-bar'; +import { StyleSheet, Text, View, Button, Alert, ScrollView } from 'react-native'; +import { authorize, AuthConfiguration, AuthorizeResult } from 'react-native-app-auth'; + +// Demo configuration using Duende IdentityServer demo +// For production, replace with your OAuth provider details +const config: AuthConfiguration = { + issuer: 'https://demo.duendesoftware.com', + clientId: 'interactive.public', + redirectUrl: 'io.identityserver.demo:/oauthredirect', + additionalParameters: {}, + scopes: ['openid', 'profile', 'email', 'offline_access'] as const, +}; + +export default function App() { + const [authState, setAuthState] = useState(null); + const [loading, setLoading] = useState(false); + + const handleAuthorize = async (): Promise => { + try { + setLoading(true); + const result = await authorize(config); + setAuthState(result); + Alert.alert('Success', 'Authentication successful!'); + } catch (error) { + console.error('Auth error:', error); + Alert.alert('Error', `Authentication failed: ${(error as Error).message}`); + } finally { + setLoading(false); + } + }; + + const handleLogout = (): void => { + setAuthState(null); + Alert.alert('Logged out', 'You have been logged out successfully'); + }; + + return ( + + React Native App Auth - Expo CNG Demo + + + Authentication Status + + {authState ? 'Authenticated' : 'Not authenticated'} + + + + {!authState ? ( +