Skip to content

Custom callback schemes for desktop using deep links #121

Open
@Robert-Stackflow

Description

@Robert-Stackflow

The package protocol_handler is used to register and handle custom protocols, which also supports desktop platforms.So I thought I could implement the redirect callback through this plugin.The example code is as follows:

import 'dart:async';

import 'package:flutter_web_auth_2_platform_interface/flutter_web_auth_2_platform_interface.dart';
import 'package:protocol_handler/protocol_handler.dart';
import 'package:url_launcher/url_launcher.dart';

/// Implements the plugin interface using an internal server
class AuthProtocolListener implements ProtocolListener {
  /// Creates a new instance of the [AuthProtocolListener]
  const AuthProtocolListener(this.onReceivedUrl);

  /// Callback for when a URL is received
  final Function(String) onReceivedUrl;

  @override
  Future<void> onProtocolUrlReceived(String url) async {
    onReceivedUrl.call(url);
  }
}

/// Implements the plugin interface using an internal server (currently used by
/// Windows and Linux).
class FlutterWebAuth2ProtocolPlugin extends FlutterWebAuth2Platform {
  /// Registers the server implementation.
  FlutterWebAuth2ProtocolPlugin() {
    _protocolListener = AuthProtocolListener((url) async {
      if (url.contains(_callbackUrl)) {
        _handleUriCallback(url);
        protocolHandler.removeListener(_protocolListener);
      }
    });
  }

  ///[optional] CallbackUrl is used to match whether the received URI
  ///matches the redirect address
  String _callbackUrl = '';
  late AuthProtocolListener _protocolListener;

  Completer<String>? _completer;

  void _handleUriCallback(String uri) {
    if (_completer != null && !_completer!.isCompleted) {
      _completer!.complete(uri);
    }
  }

  @override
  Future<String> authenticate({
    required String url,
    required String callbackUrl,
    required String callbackUrlScheme,
    required Map<String, dynamic> options,
  }) async {
    _callbackUrl = callbackUrl;
    protocolHandler.addListener(_protocolListener);
    ///Block the thread until the _handleUriCallback method is actively called
    _completer = Completer<String>();

    await launchUrl(Uri.parse(url));

    return _completer!.future;
  }

  @override
  Future clearAllDanglingCalls() async {
    ///If the user cancels the authentication process, the _completer will
    ///never be completed. This will cause the thread to hang indefinitely.
    ///This method is used to clear all dangling calls.
    _handleUriCallback('');
  }
}
  1. Before performing this operation, developers need to modify their code according to protocol_handler to support the application receiving the URI.At the same time, developers also need to pay attention to registering the same schemes as the parameter callbackUrlScheme of the authenticate function.
  2. To avoid receiving an incorrect callback URI, you can match the received URI by specifying the callbackUrl.
  3. By using custom callback schemes, developers can avoid security risks caused by loopback addresses.For example, Google has disabled the use of loopback addresses as redirect url.
  4. Compared with the method using Webview, the oauth flow of this method is more similar with the oauth flow of other native Windows applications. Moreover, when I use Webview, I will encounter the problem of application crashing.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions