react-native-app-auth

repository·main·Indexed 25 days ago

https://github.com/formidablelabs/react-native-app-auth

A React Native bridge for the native AppAuth iOS and Android SDKs, enabling secure OAuth2 and OpenID Connect authentication. It supports the Authorization Code Flow and PKCE, following RFC 8252 best practices by using ASWebAuthenticationSession, SFSafariViewController, and Custom Tabs instead of WebViews. Compatible with react-native@0.63+ and includes a config plugin for Expo Continuous Native Generation (CNG).

Tokens
27.7K
Snippets
71
Records
121
Agent score
80%

What's inside react-native-app-auth

  1. Overview of react-native-app-auth

    main

    react-native-app-auth is a React Native bridge for the AppAuth-iOS and AppAuth-Android SDKs. It is used to communicate with OAuth 2.0 and OpenID Connect providers.

    Key Features

    • Security: Follows RFC 8252 - OAuth 2.0 for Native Apps best practices. It uses ASWebAuthenticationSession and SFSafariViewController on iOS, and Custom Tabs on Android. It explicitly does not support WebView for security reasons.
    • PKCE Support: Supports the PKCE extension to secure authorization codes in public clients using custom URI scheme redirects.
    • Supported Flow: This library only supports the Authorization Code Flow.
    • Compatibility: Supports react-native@0.63+.
  2. Handle non-compliant providers with useNonce and usePKCE

    main

    Some OAuth2/OIDC providers may not strictly follow the protocol. You can adjust these settings to support them:

    • useNonce: (Default: true) Set to false to stop sending the nonce parameter. To use a custom nonce, pass it via additionalParameters: { nonce: 'your-nonce' }.
    • usePKCE: (Default: true) Set to false to stop sending the code_challenge parameter and skip PKCE verification.
  3. Configure serviceConfiguration for manual endpoint setup

    main

    Use serviceConfiguration if your provider does not support OIDC discovery or if you want to avoid the extra network round trip to fetch configuration. If issuer is not provided, serviceConfiguration becomes mandatory.

    Required fields within serviceConfiguration are authorizationEndpoint and tokenEndpoint.

  4. Security warning regarding Client Secrets

    main

    The authors of the AppAuth library strongly recommend avoiding the use of static client secrets in native applications. Static client secrets can be extracted from your app, allowing attackers to impersonate your application and potentially steal user data.

    Best Practices:

    1. Dynamic Client Registration: Use client secrets derived via dynamic client registration if possible, as these are safer.
    2. Backend Code Exchange: If your OAuth2 provider requires a client secret, the most secure pattern is to perform the code exchange step on your backend server. This keeps the secret hidden from the client-side application.
  5. Manual iOS Setup: Configure AppDelegate for Objective-C (React Native >= 0.68)

    main

    For projects using Objective-C AppDelegate, modify AppDelegate.mm to implement the RNAppAuthAuthorizationFlowManager protocol and handle URL redirection.

    + #import <React/RCTLinkingManager.h>
    + #import "RNAppAuthAuthorizationFlowManager.h"
    
    - @interface AppDelegate : RCTAppDelegate
    + @interface AppDelegate : RCTAppDelegate <RNAppAuthAuthorizationFlowManager>
    
    + @property(nonatomic, weak) id<RNAppAuthAuthorizationFlowManagerDelegate> authorizationFlowManagerDelegate;
    
    + - (BOOL) application: (UIApplication *)application
    +              openURL: (NSURL *)url
    +              options: (NSDictionary<UIApplicationOpenURLOptionsKey, id> *) options
    + {
    +   if ([self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]) {
    +     return YES;
    +   }
    +   return [RCTLinkingManager application:application openURL:url options:options];
    + }
    
    + - (BOOL) application: (UIApplication *) application
    + continueUserActivity: (nonnull NSUserActivity *)userActivity
    +   restorationHandler: (nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _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];
    + }
  6. Configure Android Redirect Scheme for Google OAuth

    main

    To allow the Android app to capture the authorization redirect from Google, you must add a manifestPlaceholder to your android/app/build.gradle file.

    The appAuthRedirectScheme must match your custom URI scheme, which follows the pattern com.googleusercontent.apps.YOUR_GOOGLE_OAUTH_APP_GUID.

    You can find this scheme in the Google Cloud Console under APIs & Services -> Credentials -> OAuth 2.0 Client IDs -> [Your Client Name] -> Advanced Settings.

    android {
      defaultConfig {
        manifestPlaceholders = [
          appAuthRedirectScheme: 'com.googleusercontent.apps.YOUR_GOOGLE_OAUTH_APP_GUID'
          // your url will look like com.googleusercontent.apps.12345678912-k50abcdefghijkabcdefghijkabcdefv
        ]
      }
    }
  7. Manual iOS Setup: Configure AppDelegate for Swift (React Native >= 0.77)

    main

    For modern React Native projects using Swift AppDelegate, follow these steps to bridge to the Objective-C code required by the library:

    1. Create AppDelegate+RNAppAuth.h and add: #import "RNAppAuthAuthorizationFlowManager.h"
    2. Set the Objective-C Bridging Header path in Xcode Build Settings to this file.
    3. Update AppDelegate.swift to conform to RNAppAuthAuthorizationFlowManager and handle the open url and continue userActivity callbacks.
    @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 RCTLinkingManager.application(app, open: url, options: options)
      }
    
      // Handle Universal Links
      func application(
        _ application: UIApplication, 
        continue userActivity: NSUserActivity, 
        restorationHandler: @escaping ([UIUserActivityRestoring]?)
      ) -> Bool {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb, 
          let delegate = authorizationFlowManagerDelegate, 
          delegate.resumeExternalUserAgentFlow(with: userActivity.webpageURL) 
        {
          return true
        }
        return RCTLinkingManager.application(
          application, 
          continue: userActivity, 
          restorationHandler: restorationHandler
        )
      }
    }
  8. Configure Coinbase OAuth

    main

    To use Coinbase with react-native-app-auth, you must first create a new OAuth application in the Coinbase console.

    Note down your clientId and clientSecret (the secret is only shown once). Ensure your redirectUrl matches the URI configured in your Coinbase application settings. For Coinbase, you must provide the specific serviceConfiguration endpoints.

    const config = {
      clientId: '<your-client-id>',
      clientSecret: '<your-client-secret>',
      redirectUrl: 'myapp://redirect', // this can be any valid uri as long as it's the same as what you configured
      scopes: ['wallet:accounts:read'], // https://developers.coinbase.com/docs/wallet/permissions
      serviceConfiguration: {
        authorizationEndpoint: 'https://www.coinbase.com/oauth/authorize',
        tokenEndpoint: 'https://api.coinbase.com/oauth/token',
        revocationEndpoint: 'https://api.coinbase.com/oauth/revoke',
      },
    };
  9. Prefetch authorization configuration on Android

    main

    On Android, you can optionally prefetch the authorization service configuration to speed up subsequent calls to authorize. This is achieved by calling prefetchConfiguration with your provider's configuration object.

    Note that this feature is only supported on Android.

    import { prefetchConfiguration } from 'react-native-app-auth';
    
    const config = {
      warmAndPrefetchChrome: true,
      issuer: '<YOUR_ISSUER_URL>',
      clientId: '<YOUR_CLIENT_ID>',
      redirectUrl: '<YOUR_REDIRECT_URL>',
      scopes: ['<YOUR_SCOPES_ARRAY>'],
    };
    
    prefetchConfiguration(config);
  10. Configure AWS Cognito for react-native-app-auth

    main

    To use AWS Cognito with this library, you must configure your User Pool in the AWS Console with the following settings:

    1. App Client: Create a new client under App clients. Crucial: Create the client without a client secret, as secrets are redundant and insecure on mobile devices. Note your <CLIENT_ID>.
    2. Domain Name: Under App Integration -> Domain Name, set up a domain. Your domain will follow the pattern: https://<your-domain>.auth.<region>.amazoncognito.com.
    3. App Client Settings: Under App Integration -> App Client Settings, ensure the following are configured:
      • Enabled Identity Providers: Enable your user pool.
      • Callback URL: Add your app's redirect URI (e.g., com.myclientapp://myclient/redirect). This must exactly match the redirectUrl in your code configuration.
      • Grants: Enable the Authorization code grant.
      • Scopes: Enable openid scope.
  11. Configure Android App Links

    main

    If your OAuth Redirect URL uses App Links, you must add a RedirectUriReceiverActivity to your AndroidManifest.xml with an intent filter configured for your domain.

    1. Add the activity to AndroidManifest.xml:
    <activity
      android:name="net.openid.appauth.RedirectUriReceiverActivity"
      android:exported="true">
      <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="https" android:host=example.domain />
      </intent-filter>
    </activity>
    1. Set the manifestPlaceholders in android/app/build.gradle using the host part of your redirect URI:
    android {
      defaultConfig {
        manifestPlaceholders = [
          appAuthRedirectScheme: 'example.domain'
        ]
      }
    }
  12. Revoke Strava tokens manually

    main

    The built-in token revocation method in react-native-app-auth is not compatible with Strava because Strava expects the parameter access_token instead of the standard token.

    You must implement revocation manually using fetch by sending a POST request to the Strava deauthorize endpoint with the access_token as a query parameter.

    const res = await fetch(`https://www.strava.com/oauth/deauthorize?access_token=${accessToken}`, {
      method: 'POST',
    });