'How to catch OAuth2 token in Flutter Web?

This dependency supposedly supports web, but the implementation to listen for the callback and retrieve the token is missing. After digging around for the last three days, a few people suggested that it would work using the dart:html library, with onMessage, and postMessage functions.

Here's my setup:

import 'dart:html' as html;
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:oauth2/oauth2.dart' as oauth2;
import 'package:url_launcher/url_launcher.dart';

class AuthYoutube {
var httpClient = http.Client();
  Future<oauth2.Client> getClient() async {
    var grant = new oauth2.AuthorizationCodeGrant(
        CLIENT_ID, AUTH_DOMAIN, AUTH_TOKEN,
        secret: secret);
    var authorizationUrl =
        grant.getAuthorizationUrl(REDIRECT_URI, scopes: scopes);

    html.window.open(authorizationUrl.toString(), "open");
    Completer<LinkedHashMap<dynamic, dynamic>> completer = Completer();
    html.window.onMessage.listen((event) async {
      completer.complete(event.data as LinkedHashMap<dynamic, dynamic>);
    });
    Uri responseUri;
    completer.future.then((value) {
      responseUri = Uri.parse(value.toString());
      return grant.handleAuthorizationResponse(responseUri.queryParameters);
    });
  }

} And the separate route set as the callback URL:

class Special extends StatelessWidget {
  static String route = "/special";
  @override
  Widget build(BuildContext context) {
    final loc = Uri.parse(html.window.location.href);
    final code = loc.queryParameters["code"];
    print("code $code");
    html.window.postMessage(code, html.window.location.origin);
    return Text("All done");
  }
}

What ends up happening is the auth token shows up in the address bar at the last step. I can see it in there after ?code=, but it doesn't get printed out. The listen method gets triggered 5-6 times throughout the entire flow (while clicking on "allow" in the other window). In the console, I only get this one error:

Uncaught (in promise) Error: Bad state: Future already completed
    at Object.throw_ [as throw] (errors.dart:212)
    at _AsyncCompleter.new.complete (future_impl.dart:43)
    at authYT.dart:41
    at Generator.next (<anonymous>)
    at runBody (async_patch.dart:84)
    at Object._async [as async] (async_patch.dart:123)
    at authYT.dart:40
    at Object._checkAndCall (operations.dart:324)
    at Object.dcall (operations.dart:329)
    at html_dart2js.dart:37246


Solution 1:[1]

You can capture the access token in the onGenerateRoute method through the URL.

Here’s a link to the blog that does it properly: https://aws.plainenglish.io/oauth2-in-flutter-web-using-aws-cognito-f7051be92bdf

Solution 2:[2]

There is a new plugin Flutter plugin that supports the complete authentication flow in web and also on mobile:

https://pub.dev/packages/flutter_web_auth

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Muhammad Shahrukh
Solution 2 Jeff S.