This plugin offers a WebView implementation approach for OAuth authorization/authentication with identity providers. In the case of Web it doesn't use WebView, instead it loads the page directly in the browser.
Platform | Compatibility |
---|---|
Android | :white_check_mark: |
iOS | :white_check_mark: |
Web | :white_check_mark: |
Other plugins like Flutter AppAuth uses native implementation of AppAuth which in turn uses SFAuthenticationSession
and CustomTabs
for iOS and Android respectively. When using SFAuthenticationSession
and CustomTabs
your app will/could present some problems like:
With this plugin you will get:
contentLocale
property to ensure the same locale. By default Operating System locale will be used if no contentLocale
is specified.Notes:
contentLocale
will apply only if the authentication page supports the specified Locale('...')
and accepts the header: 'Accept-Language': 'es-ES'
.contentLocale
, custom headers, custom UserAgent, nor full control over UI, because web implementation loads the page directly in the browser.OAuthWebView
to BaseWebView
OAuthWebView
renamed onSuccess
function to onSuccessAuth
.Probably you will not need to do any migration. You only need to do changes:
BaseWebView
to BaseConfiguration
.OAuthWebScreen
and OAuthWebView
now requires a OAuthConfiguration
object and BaseWebScreen
and BaseWebView
now requires a BaseConfiguration
object instead of properties directly.environment
fits the following constraints: sdk: ">=2.19.0 <3.0.0"
and flutter: ">=2.0.0"
.OAuthWebAuth.clearAll({BuildContext? context, InAppWebViewController? controller})
to OAuthWebAuth.clearAll()
, no params required.OAuthWebAuth.clearCache({BuildContext? context, InAppWebViewController? controller})
to OAuthWebAuth.clearCache()
, no params required.flutter_inappwebview: ^6.0.0
which already supports web, it's required (only if your project supports web) to include a script in the index.html
like: <script type="application/javascript" src="https://github.com/luis901101/oauth_webauth/raw/master/assets/packages/flutter_inappwebview_web/assets/web/web_support.js" defer></script>
, anyway we recommend you to check the readme of flutter_inappwebview for more details.environment
fits the following constraints: sdk: ">=3.0.0 <4.0.0"
and flutter: '>=3.3.0'
.As stated before this plugin uses WebView implementation specifically the plugin flutter_inappwebview. For any WebView related problem please check the documentation of that plugin at docs.
Just add the internet permission to your AndroidManifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.example">
<uses-permission android:name="android.permission.INTERNET"/>
<application>
...
</application>
Just add this to your Info.plist
<plist version="1.0">
<dict>
....
....
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
....
....
</dict>
</plist>
To make it work properly on the Web platform, you need to add the web_support.js
file inside the <head>
of your web/index.html
file:
<head>
<!-- ... -->
<script type="application/javascript" src="https://github.com/luis901101/oauth_webauth/raw/master/assets/packages/flutter_inappwebview_web/assets/web/web_support.js" defer></script>
<!-- ... -->
</head>
OAuthWebView
which handles all the authorization/authentication and navigation logic; this widget can be used in any widget tree of your current app or as an individual authentication screen. For individual authentication screen it offers the widget OAuthWebScreen
which can be started as a new route and also handles the Android back button to navigate backward when applies.BaseWebView
which may be useful for cases in which you need to handle a link to your Auth server, let's say for email confirmation, or password reset, etc. This widget will handle the web UI and automatically get back to you when loaded any of the specified redirectUrls
. The BaseWebView
widget works very similar to OAuthWebView
, it can be used in any widget tree of your current app or as an individual screen. For individual screen it offers the widget BaseWebScreen
which can be started as a new route and also handles the Android back button to navigate backward when applies.In the main()
function you should initialize this plugin just before runApp(...):
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await OAuthWebAuth.instance.init();
runApp(const MyApp());
}
WidgetsFlutterBinding.ensureInitialized();
before .init()
. In the case of testing TestWidgetsFlutterBinding.ensureInitialized()
should be called.This plugin offers two variants to handle these outputs.
Awaiting response from navigator route Future
.
void loginV1() async {
final result = await OAuthWebScreen.start(
context: context,
configuration: OAuthConfiguration(
authorizationEndpointUrl: authorizationEndpointUrl,
tokenEndpointUrl: tokenEndpointUrl,
clientSecret: clientSecret,
clientId: clientId,
redirectUrl: redirectUrl,
scopes: scopes,
promptValues: const ['login'],
loginHint: 'johndoe@mail.com',
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
BaseConfiguration.backButtonTooltipKey: 'Ir atrás',
BaseConfiguration.forwardButtonTooltipKey: 'Ir adelante',
BaseConfiguration.reloadButtonTooltipKey: 'Recargar',
BaseConfiguration.clearCacheButtonTooltipKey: 'Limpiar caché',
BaseConfiguration.closeButtonTooltipKey: 'Cerrar',
BaseConfiguration.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
},
contentLocale: Locale('es'),
refreshBtnVisible: false,
clearCacheBtnVisible: false,
));
if (result != null) {
if (result is Credentials) {
authResponse = getPrettyCredentialsJson(result);
} else {
authResponse = result.toString();
}
} else {
authResponse = 'User cancelled authentication';
}
setState(() {});
}
Using callbacks
void loginV2() {
OAuthWebScreen.start(
context: context,
configuration: OAuthConfiguration(
authorizationEndpointUrl: authorizationEndpointUrl,
tokenEndpointUrl: tokenEndpointUrl,
clientSecret: clientSecret,
clientId: clientId,
redirectUrl: redirectUrl,
scopes: scopes,
promptValues: const ['login'],
loginHint: 'johndoe@mail.com',
onCertificateValidate: (certificate) {
///This is recommended
/// Do certificate validations here
/// If false is returned then a CertificateException() will be thrown
return true;
},
textLocales: {
///Optionally text can be localized
BaseConfiguration.backButtonTooltipKey: 'Ir atrás',
BaseConfiguration.forwardButtonTooltipKey: 'Ir adelante',
BaseConfiguration.reloadButtonTooltipKey: 'Recargar',
BaseConfiguration.clearCacheButtonTooltipKey: 'Limpiar caché',
BaseConfiguration.closeButtonTooltipKey: 'Cerrar',
BaseConfiguration.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
},
contentLocale: Locale('es'),
refreshBtnVisible: false,
clearCacheBtnVisible: false,
onSuccessAuth: (credentials) {
isLoading = false;
setState(() {
authResponse = getPrettyCredentialsJson(credentials);
});
},
onError: (error) {
isLoading = false;
setState(() {
authResponse = error.toString();
});
},
onCancel: () {
isLoading = false;
setState(() {
authResponse = 'User cancelled authentication';
});
}),
);
}
This plugin offers two variants to handle these outputs.
Awaiting response from navigator route Future
.
void baseRedirectV1() async {
final result = await BaseWebScreen.start(
context: context,
configuration: BaseConfiguration(
initialUrl: initialUrl,
redirectUrls: [redirectUrl, baseUrl],
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
BaseConfiguration.backButtonTooltipKey: 'Ir atrás',
BaseConfiguration.forwardButtonTooltipKey: 'Ir adelante',
BaseConfiguration.reloadButtonTooltipKey: 'Recargar',
BaseConfiguration.clearCacheButtonTooltipKey: 'Limpiar caché',
BaseConfiguration.closeButtonTooltipKey: 'Cerrar',
BaseConfiguration.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
},
contentLocale: Locale('es'),
refreshBtnVisible: false,
clearCacheBtnVisible: false,
),
);
if (result != null) {
if (result is String) {
/// If result is String it means redirected successful
response = 'User redirected to: $result';
} else {
/// If result is not String then some error occurred
response = result.toString();
}
} else {
/// If no result means user cancelled
response = 'User cancelled';
}
setState(() {});
}
Using callbacks
void baseRedirectV2() {
BaseWebScreen.start(
context: context,
configuration: BaseConfiguration(
initialUrl: initialUrl,
redirectUrls: [redirectUrl, baseUrl],
onCertificateValidate: (certificate) {
///This is recommended
/// Do certificate validations here
/// If false is returned then a CertificateException() will be thrown
return true;
},
textLocales: {
///Optionally text can be localized
BaseConfiguration.backButtonTooltipKey: 'Ir atrás',
BaseConfiguration.forwardButtonTooltipKey: 'Ir adelante',
BaseConfiguration.reloadButtonTooltipKey: 'Recargar',
BaseConfiguration.clearCacheButtonTooltipKey: 'Limpiar caché',
BaseConfiguration.closeButtonTooltipKey: 'Cerrar',
BaseConfiguration.clearCacheWarningMessageKey:
'¿Está seguro que desea limpiar la caché?',
},
contentLocale: Locale('es'),
refreshBtnVisible: false,
clearCacheBtnVisible: false,
onSuccessRedirect: (responseRedirect) {
setState(() {
response = 'User redirected to: $responseRedirect';
});
},
onError: (error) {
setState(() {
response = error.toString();
});
},
onCancel: () {
setState(() {
response = 'User cancelled';
});
}),
);
}
goBackBtnVisible
, goForwardBtnVisible
, refreshBtnVisible
, clearCacheBtnVisible
, closeBtnVisible
allows you to show/hide buttons from toolbar, if you want to completely hide toolbar, set all buttons to false.urlStream
when you need to asynchronously navigate to a specific url, like when user registered using OAuthWebAuth
and the web view waits for user email verification; in this case when the user opens the email verification link you can navigate to this link by emitting the new url to the stream you previously set in the urlStream
instead of creating a new OAuthWebAuth
or BaseWebView
.OAuthWebAuth.instance
, like OAuthWebAuth.instance.clearCache()
, OAuthWebAuth.instance.clearCookies()
or OAuthWebAuth.instance.clearAll()
.Note: It should work with any OAuth2 comatible service that uses Authorization Code Grant