Skip to content

Commit

Permalink
馃挜 Add Web support (LinusU#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
czepiec committed Aug 9, 2021
1 parent 9af584d commit d233d81
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 2 deletions.
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A Flutter plugin for authenticating a user with a web service, even if the web service is run by a third party. Most commonly used with OAuth2, but can be used with any web flow that can redirect to a custom scheme.

In the background, this plugin uses [`ASWebAuthenticationSession`][ASWebAuthenticationSession] on iOS 12+ and macOS 10.15+, [`SFAuthenticationSession`][SFAuthenticationSession] on iOS 11, and [Chrome Custom Tabs][Chrome Custom Tabs] on Android. You can build it with iOS 8+, but it is currently only supported by iOS 11 or higher.
In the background, this plugin uses [`ASWebAuthenticationSession`][ASWebAuthenticationSession] on iOS 12+ and macOS 10.15+, [`SFAuthenticationSession`][SFAuthenticationSession] on iOS 11, [Chrome Custom Tabs][Chrome Custom Tabs] on Android and opens a new window on Web. You can build it with iOS 8+, but it is currently only supported by iOS 11 or higher.

[ASWebAuthenticationSession]: https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession
[SFAuthenticationSession]: https://developer.apple.com/documentation/safariservices/sfauthenticationsession
Expand Down Expand Up @@ -70,7 +70,7 @@ final accessToken = jsonDecode(response.body)['access_token'] as String;

## Setup

Setup works as for any Flutter plugin, expect the Android caveat outlined below:
Setup works as for any Flutter plugin, expect the Android and Web caveats outlined below:

### Android

Expand All @@ -92,3 +92,22 @@ In order to capture the callback url, the following `activity` needs to be added
</application>
</manifest>
```

### Web

On the Web platform an endpoint needs to be created that captures the callback URL and sends it to the application using the JavaScript `postMessage()` method. In the `./web` folder of the project, create an HTML file with the name e.g. `flutter-web-auth.html` with content:

```html
<!DOCTYPE html>
<title>Authentication complete</title>
<p>Authentication is complete. If this does not happen automatically, please
close the window.
<script>
window.opener.postMessage({
'flutter-web-auth': window.location.href
}, window.location.origin);
window.close();
</script>
```

Redirection URL passed to the authentication service must be the same as the URL on which the application is running (schema, host, port if necessary) and the path must point to created HTML file, `/flutter-web-auth.html` in this case. The `callbackUrlScheme` parameter of the `authenticate()` method does not take into account, so it is possible to use a schema for native platforms in the code.
15 changes: 15 additions & 0 deletions example/lib/generated_plugin_registrant.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//

// ignore_for_file: lines_longer_than_80_chars

import 'package:flutter_web_auth/src/flutter_web_auth_web.dart';

import 'package:flutter_web_plugins/flutter_web_plugins.dart';

// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
FlutterWebAuthPlugin.registerWith(registrar);
registrar.registerMessageHandler();
}
Binary file added example/web/favicon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions example/web/flutter-web-auth.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<title>Authentication complete</title>
<p>Authentication is complete. If this does not happen automatically, please
close the window.
<script>
window.opener.postMessage({
'flutter-web-auth': window.location.href
}, window.location.origin);
window.close();
</script>
Binary file added example/web/icons/Icon-192.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/web/icons/Icon-512.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions example/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
Fore more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
-->
<base href="/">

<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">

<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="example">
<link rel="apple-touch-icon" href="icons/Icon-192.png">

<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>

<title>example</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('flutter-first-frame', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
});
}
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions example/web/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "example",
"short_name": "example",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
42 changes: 42 additions & 0 deletions lib/src/flutter_web_auth_web.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'dart:async';
import 'dart:html';
import 'dart:js';

import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

class FlutterWebAuthPlugin {
static void registerWith(Registrar registrar) {
final MethodChannel channel = MethodChannel(
'flutter_web_auth', const StandardMethodCodec(), registrar.messenger);
final FlutterWebAuthPlugin instance = FlutterWebAuthPlugin();
channel.setMethodCallHandler(instance.handleMethodCall);
}

Future<dynamic> handleMethodCall(MethodCall call) async {
switch (call.method) {
case 'authenticate':
final String url = call.arguments['url'];
return _authenticate(url);
default:
throw PlatformException(
code: 'Unimplemented',
details: "The flutter_web_auth plugin for web doesn't implement "
"the method '${call.method}'");
}
}

static Future<String> _authenticate(String url) async {
context.callMethod('open', [url]);
await for (MessageEvent messageEvent in window.onMessage) {
if (messageEvent.origin == Uri.base.origin) {
final flutterWebAuthMessage = messageEvent.data['flutter-web-auth'];
if (flutterWebAuthMessage is String) {
return flutterWebAuthMessage;
}
}
}
throw new PlatformException(
code: 'error', message: 'Iterable window.onMessage is empty');
}
}
5 changes: 5 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter

dev_dependencies:
flutter_test:
Expand All @@ -33,6 +35,9 @@ flutter:
pluginClass: FlutterWebAuthPlugin
macos:
pluginClass: FlutterWebAuthPlugin
web:
pluginClass: FlutterWebAuthPlugin
fileName: src/flutter_web_auth_web.dart

# To add assets to your plugin package, add an assets section, like this:
# assets:
Expand Down

0 comments on commit d233d81

Please sign in to comment.