oauth2_client icon indicating copy to clipboard operation
oauth2_client copied to clipboard

App not being redirected to the right redirectUri

Open jaybconsulting opened this issue 1 year ago • 2 comments

BACKGROUND I'm relatively new to Flutter and trying to build a new app from scratch (currently just in development and only testing on Android right now) using the oauth2_client package to allow the user to connect the app with their Intuit Quickbooks account. The app correctly opens the authentication window and allows the user to log in to their Quickbooks.

ISSUE After log in, Android navigates back to the app but it doesn't navigate back to the correct screen based on the redirectUri passed to the OAuth2Client, it instead navigates back to the screen where the user initiated the authentication. I can't figure out why this is happening.

CODE

app_routes.dart

final router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const AuthGate(),
      routes: [
        GoRoute(
          path: 'about',
          builder: (context, state) {
            if(state.uri.queryParameters['realmId'] != null)
            {
              Provider.of<BooksmartOAuthHelper>(context, listen: false).setQuickbooksRealmId(state.uri.queryParameters['realmId']!);
            }

            return const AboutPage();
          },
        ),
      ],
    ),
  ],
);

The authentication is initiated with this code from my HomeScreen:

onTap: () {
  Provider.of<BooksmartOAuthHelper>(context, listen: false).authenticateOAuth2Helper(app, context);
},

And here's BooksmartOAuthHelper (I just made this wrapper so I could use it in a Provider at the top level of my app without having to instantiate the OAuth2Helper):

class BooksmartOAuthHelper {
  OAuth2Helper? oauth2Helper;
  String? quickbooksRealmId;

  BooksmartOAuthHelper();

  void authenticateOAuth2Helper(String accountingApp, BuildContext context) async {
    switch (accountingApp) {
      case 'Quickbooks':
        IntuitOAuth2Client client = IntuitOAuth2Client(
          redirectUri: 'https://booksmart-6870c.web.app/about',
          customUriScheme: 'https'
        );

        oauth2Helper = OAuth2Helper(
          client,
          grantType: OAuth2Helper.authorizationCode,
          clientId: intuitClientId,
          clientSecret: intuitClientSecret,
          scopes: ['com.intuit.quickbooks.accounting', 'com.intuit.quickbooks.payment'],
        );

        await oauth2Helper!.fetchToken();
    default:
      throw UnimplementedError('$accountingApp is not supported yet');
    }
  }
}

The authentication window correctly pops up when authenticateOAuth2Helper is called and allows the user to log in.

Here's my custom OAuth2Client:

class IntuitOAuth2Client extends OAuth2Client {
  IntuitOAuth2Client({required super.redirectUri, required super.customUriScheme}): 
  super(
    authorizeUrl: 'https://appcenter.intuit.com/connect/oauth2',
    tokenUrl: 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer'
  );
}

Here's a code snippet from my AndroidManifest.xml:

<manifest ...>
    <application ...>
        <activity android:name=".MainActivity" ...>
        </activity>
        <meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
        <activity android:name="com.linusu.flutter_web_auth_2.CallbackActivity" android:exported="true">
            <intent-filter android:label="flutter_web_auth_2" 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="booksmart-6870c.web.app" 
                    android:pathPrefix="/about" />
                <data android:scheme="http" />
            </intent-filter>
        </activity>
</manifest>

Also, since Quickbooks requires an http or https scheme, I've set up my callback URI as an App Link. I'm hosting a dummy website on Firebase Hosting (https://booksmart-6870c.web.app) and the web server contains the /.well-known/assetlinks.json so Android knows to redirect these URL calls to my app.

Last possibly interesting piece: Before I added the " ... " to the AndroidManifest.xml and instead had the same intent-filter in the MainActivity, the authentication wasn't working but after the authentication failed I would still get redirected to my AboutPage with the correct query parameters.

PROBLEM QUESTION Does anyone know why my app isn't correctly redirecting to the AboutPage (the end of the redirect URI based on my GoRouter)? It's instead redirecting back to the HomePage on the app (where the authentication was initiated). I need to get the query parameters from the redirect URI, but because the redirect URI isn't being handled by my app correctly I'm unable to get those parameters.

jaybconsulting avatar Jun 06 '24 21:06 jaybconsulting

I have the same problem.

After login, redirect failed with following exception : No stored state - unable to handle response

I think the problem is general, I tried flutter_appauth package and got the same exception. https://github.com/MaikuB/flutter_appauth/issues/503

leutbounpaseuth avatar Jun 12 '24 15:06 leutbounpaseuth

There seems to be a solution in MaikuB/flutter_appauth/issues/503, thanks to @leutbounpaseuth.

georgekal2798 avatar Jun 14 '24 15:06 georgekal2798