Skip to content

Commit

Permalink
- contentLocale property can be set to indicate the web auth to use…
Browse files Browse the repository at this point in the history
… that locale for internationalization.
  • Loading branch information
luis901101 committed Mar 2, 2022
1 parent dd291c3 commit 2479672
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .pubignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
.packages
.pub-cache/
.pub/
/build/
build/
.flutter-plugins
.flutter-plugins-dependencies
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Types of changes
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## 1.1.0+3 (2022-03-02)
### Added
- `contentLocale` property can be set to indicate the web auth to use that locale for internationalization.

## 1.0.0+2
### Changed
- README updated
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ Other plugins like [Flutter AppAuth](https://pub.dev/packages/flutter_appauth) u
- UI: users will notice a breaking UI difference when system browser opens to handle the identity provider authentication process.
- In iOS an annoying system dialog shows up every time the user tries to authenticate, indicating that the current app and browser could share their information.
- Your system browser cache is shared with your app which is good and **bad**, bad because any cache problem due to your every day navigation use could affect your app authentication and the only way to clean cache it's by cleaning system browser cache at operating system level.
- Authentication page will use the locale from System Browser which in fact uses the Operating System locale, this means if your app uses different language than the Operating System then authentication page will show different internationalization than your app.

## Features

With this plugin you will get:
- Full control over the UI, WebView will run inside your app so Theme and Color Scheme will be yours to choose, in fact you can add AppBar or FloatingActionButton or whatever you thinks it's necessary to your UI.
- No system dialog will be shown when users tries to authenticate.
- Users will not be affected by any system browser problem cache and also will be able to clean app browser cache from the authentication screen itself.
- Authentication page locale can be set from app using the `contentLocale` property to ensure the same locale. By default Operating System locale will be used if no `contentLocale` is specified.

## Getting started
**Note:**
- `contentLocale` will apply only if the authentication page supports the specified `Locale('...')` and accepts the header: `'Accept-Language': 'es-ES'`

## Getting started
As stated before this plugin uses WebView implementation specifically the plugin [flutter_inappwebview](https://pub.dev/packages/flutter_inappwebview). For any WebView related problem please check the documentation of that plugin at [docs](https://inappwebview.dev/docs/).

### Android setup
Expand Down Expand Up @@ -88,6 +91,7 @@ void loginV1() async {
/// If false is returned then a CertificateException() will be thrown
return true;
},
contentLocale: Locale('es'),
textLocales: {
///Optionally texts can be localized
OAuthWebView.backButtonTooltipKey: 'Ir atrás',
Expand Down Expand Up @@ -131,6 +135,7 @@ void loginV2() {
/// If false is returned then a CertificateException() will be thrown
return true;
},
contentLocale: Locale('es'),
textLocales: {
///Optionally text can be localized
OAuthWebView.backButtonTooltipKey: 'Ir atrás',
Expand Down
2 changes: 1 addition & 1 deletion example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
.packages
.pub-cache/
.pub/
/build/
build/

# Web related
lib/generated_plugin_registrant.dart
Expand Down
2 changes: 1 addition & 1 deletion example/.pubignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
.packages
.pub-cache/
.pub/
/build/
build/
.flutter-plugins
.flutter-plugins-dependencies
6 changes: 4 additions & 2 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 51;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -76,7 +76,6 @@
E0DAAC17531E652E02363B34 /* Pods-Runner.release.xcconfig */,
47363B92604AC4D5C9BCBE9B /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
Expand Down Expand Up @@ -356,6 +355,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = PT79KLNGFU;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down Expand Up @@ -484,6 +484,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = PT79KLNGFU;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
Expand All @@ -506,6 +507,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = PT79KLNGFU;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down
74 changes: 49 additions & 25 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ void main() {

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
Expand Down Expand Up @@ -49,6 +50,8 @@ class _MyHomePageState extends State<MyHomePage> {
.split(' ');

String authResponse = 'Authorization data will be shown here';
Locale? contentLocale;
final locales = const [null, Locale('es'), Locale('en')];

@override
Widget build(BuildContext context) {
Expand All @@ -65,6 +68,24 @@ class _MyHomePageState extends State<MyHomePage> {
authResponse,
),
const SizedBox(height: 16),
SizedBox(
width: 120,
child: DropdownButtonFormField<Locale>(
items: locales
.map((e) => DropdownMenuItem(
value: e,
child: Text(e?.toLanguageTag() ?? 'Default OS')))
.toList(),
value: contentLocale,
onChanged: (locale) {
setState(() {
contentLocale = locale;
});
},
decoration:
const InputDecoration(label: Text('Content language')),
),
),
ElevatedButton(
onPressed: loginV1,
child: const Text('Login variant 1'),
Expand All @@ -85,31 +106,33 @@ class _MyHomePageState extends State<MyHomePage> {

void loginV1() async {
final result = await OAuthWebScreen.start(
context: context,
authorizationEndpointUrl: authorizationEndpointUrl,
tokenEndpointUrl: tokenEndpointUrl,
clientSecret: clientSecret,
clientId: clientId,
redirectUrl: redirectUrl,
scopes: scopes,
promptValues: const ['login'],
loginHint: '[email protected]',
onCertificateValidate: (certificate) {
///This is recommended
/// Do certificate validations here
/// If false is returned then a CertificateException() will be thrown
return true;
},
textLocales: {
///Optionally texts can be localized
OAuthWebView.backButtonTooltipKey: 'Ir atrás',
OAuthWebView.forwardButtonTooltipKey: 'Ir adelante',
OAuthWebView.reloadButtonTooltipKey: 'Recargar',
OAuthWebView.clearCacheButtonTooltipKey: 'Limpiar caché',
OAuthWebView.closeButtonTooltipKey: 'Cerrar',
OAuthWebView.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
});
context: context,
authorizationEndpointUrl: authorizationEndpointUrl,
tokenEndpointUrl: tokenEndpointUrl,
clientSecret: clientSecret,
clientId: clientId,
redirectUrl: redirectUrl,
scopes: scopes,
promptValues: const ['login'],
loginHint: '[email protected]',
onCertificateValidate: (certificate) {
///This is recommended
/// Do certificate validations here
/// If false is returned then a CertificateException() will be thrown
return true;
},
textLocales: {
///Optionally texts can be localized
OAuthWebView.backButtonTooltipKey: 'Ir atrás',
OAuthWebView.forwardButtonTooltipKey: 'Ir adelante',
OAuthWebView.reloadButtonTooltipKey: 'Recargar',
OAuthWebView.clearCacheButtonTooltipKey: 'Limpiar caché',
OAuthWebView.closeButtonTooltipKey: 'Cerrar',
OAuthWebView.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
},
contentLocale: contentLocale,
);
if (result != null) {
if (result is Credentials) {
authResponse = getPrettyCredentialsJson(result);
Expand Down Expand Up @@ -149,6 +172,7 @@ class _MyHomePageState extends State<MyHomePage> {
OAuthWebView.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
},
contentLocale: contentLocale,
onSuccess: (credentials) {
setState(() {
authResponse = getPrettyCredentialsJson(credentials);
Expand Down
13 changes: 10 additions & 3 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
meta:
dependency: transitive
description:
Expand All @@ -129,14 +136,14 @@ packages:
path: ".."
relative: true
source: path
version: "1.0.0+1"
version: "1.1.0+3"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
version: "1.8.1"
plugin_platform_interface:
dependency: transitive
description:
Expand Down Expand Up @@ -197,7 +204,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
version: "0.4.9"
typed_data:
dependency: transitive
description:
Expand Down
40 changes: 23 additions & 17 deletions lib/src/oauth_web_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@ import 'package:oauth2/oauth2.dart';
import 'package:oauth_webauth/src/oauth_web_view.dart';

class OAuthWebScreen extends StatelessWidget {
static Future? start(
{Key? key,
required BuildContext context,
required String authorizationEndpointUrl,
required String tokenEndpointUrl,
required String redirectUrl,
required String clientId,
String? clientSecret,
List<String>? scopes,
String? loginHint,
List<String>? promptValues,
ValueChanged<Credentials>? onSuccess,
ValueChanged<dynamic>? onError,
VoidCallback? onCancel,
CertificateValidator? onCertificateValidate,
ThemeData? themeData,
Map<String, String>? textLocales}) =>
static Future? start({
Key? key,
required BuildContext context,
required String authorizationEndpointUrl,
required String tokenEndpointUrl,
required String redirectUrl,
required String clientId,
String? clientSecret,
List<String>? scopes,
String? loginHint,
List<String>? promptValues,
ValueChanged<Credentials>? onSuccess,
ValueChanged<dynamic>? onError,
VoidCallback? onCancel,
CertificateValidator? onCertificateValidate,
ThemeData? themeData,
Map<String, String>? textLocales,
Locale? contentLocale,
}) =>
Navigator.push(
context,
MaterialPageRoute(
Expand All @@ -38,6 +40,7 @@ class OAuthWebScreen extends StatelessWidget {
onCertificateValidate: onCertificateValidate,
themeData: themeData,
textLocales: textLocales,
contentLocale: contentLocale,
)));

final String authorizationEndpointUrl;
Expand Down Expand Up @@ -65,6 +68,7 @@ class OAuthWebScreen extends StatelessWidget {

final ThemeData? themeData;
final Map<String, String>? textLocales;
final Locale? contentLocale;

late final BuildContext context;
final paymentViewStateKey = GlobalKey<OAuthWebViewState>();
Expand All @@ -85,6 +89,7 @@ class OAuthWebScreen extends StatelessWidget {
this.onCertificateValidate,
this.themeData,
this.textLocales,
this.contentLocale,
}) : super(key: key);

@override
Expand All @@ -111,6 +116,7 @@ class OAuthWebScreen extends StatelessWidget {
onCertificateValidate: onCertificateValidate,
themeData: themeData,
textLocales: textLocales,
contentLocale: contentLocale,
),
),
);
Expand Down
9 changes: 8 additions & 1 deletion lib/src/oauth_web_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class OAuthWebView extends StatefulWidget {

final ThemeData? themeData;
final Map<String, String>? textLocales;
final Locale? contentLocale;

const OAuthWebView({
Key? key,
Expand All @@ -64,6 +65,7 @@ class OAuthWebView extends StatefulWidget {
this.onCertificateValidate,
this.themeData,
this.textLocales,
this.contentLocale,
}) : super(key: key);

@override
Expand Down Expand Up @@ -207,7 +209,12 @@ class OAuthWebViewState extends State<OAuthWebView>
/// This custom userAgent is mandatory due to security constraints of Google's OAuth2 policies (https://developers.googleblog.com/2021/06/upcoming-security-changes-to-googles-oauth-2.0-authorization-endpoint.html)
),
),
initialUrlRequest: URLRequest(url: authorizationUri),
initialUrlRequest: URLRequest(
url: authorizationUri,
headers: widget.contentLocale == null
? null
: {'Accept-Language': widget.contentLocale!.toLanguageTag()},
),
onReceivedServerTrustAuthRequest: (controller, challenge) async {
return ServerTrustAuthResponse(
action: ServerTrustAuthResponseAction.PROCEED);
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: oauth_webauth
description: This plugin provides an alternative to AppAuth using WebView for OAuth 2.0 authorization/authentication.
version: 1.0.0+2
version: 1.1.0+3
homepage: https://github.com/luis901101/oauth_webauth

environment:
Expand Down

0 comments on commit 2479672

Please sign in to comment.