Flutter Facebook Sign In (with Firebase) in 2020

A good login flow is essential for an amazing user experience. It has been possible for years now to sign in with Facebook in your flutter app.

But last year there were some ‘breaking’ changes.

Facebook SDK 6.0.0

"FBSDKLoginBehavior Login flows no longer support logging in through the native application. This change reflects that.”

Apple IOS 13 guidelines

“The App Store will no longer accept new apps using UIWebView as of April 2020 and app updates using UIWebView as of December 2020.”

The best flutter package to sign in with Facebook: flutter_facebook_login 3.0.0 uses both of them. So it’s safe to say it’s deprecated.

But every problem has a solution: we’re going to use a custom login flow from Facebook.

First, create a Facebook developer account and enable “Facebook Login”.

Important: enable these settings and the following redirect uri.

Facebook OAuth settings

This uri will receive the token in its parameters that we need.

Second, we need to enable facebook in the firebase console.

Firebase will need your app ID & your app secret (don’t share it, it’s secret).

Now we’re going to code the flutter part:

We need a few packages:

flutter_webview_plugin: ^0.3.10+1

firebase_auth: ^0.15.3

iOS In order for plugin to work correctly, you need to add new key to ios/Runner/Info.plist <key>NSAppTransportSecurity</key>

<dict>

<key>NSAllowsArbitraryLoads</key>

<true/>

<key>NSAllowsArbitraryLoadsInWebContent</key>

<true/>

</dict>

We’re going to log the user in on the special login portal of Facebook and receive a token to pass to Firebase.

But first, we need to define 2 variables. (and import the packages)

String your_client_id = "enter your app FBID here (DON'T add secret app code)";

String your_redirect_url =

"https://www.facebook.com/connect/login_success.html"; loginWithFacebook() async{

String result = await Navigator.push(

context,

MaterialPageRoute(

builder: (context) => CustomWebView(

selectedUrl:

'https://www.facebook.com/dialog/oauth?client_id=$your_client_id&redirect_uri=$your_redirect_url&response_type=token&scope=email,public_profile,',

),

maintainState: true),

);}

This function will navigate us to a WKwebview (which Apple supports) that will ask the user for his email and password.

class CustomWebView extends StatefulWidget {

final String selectedUrl;



CustomWebView({this.selectedUrl});



@override

_CustomWebViewState createState() => _CustomWebViewState();

}



class _CustomWebViewState extends State<CustomWebView> {

final flutterWebviewPlugin = new FlutterWebviewPlugin();



@override

void initState() {

super.initState();



flutterWebviewPlugin.onUrlChanged.listen((String url) {

if (url.contains("#access_token")) {

succeed(url);

}



if (url.contains(

"https://www.facebook.com/connect/login_success.html?error=access_denied&error_code=200&error_description=Permissions+error&error_reason=user_denied")) {

denied();

}

});

}



denied() {

Navigator.pop(context);

}



succeed(String url) {

var params = url.split("access_token=");



var endparam = params[1].split("&");



Navigator.pop(context, endparam[0]);

}



@override

Widget build(BuildContext context) {

return WebviewScaffold(

url: widget.selectedUrl,

appBar: new AppBar(

backgroundColor: Color.fromRGBO(66, 103, 178, 1),

title: new Text("Facebook login"),

));

}

}

What we’re doing here is simple: as a user taps the login button (after entering his email and password), facebook updates the URL and adds the token to it.

But there are 2 options, the user cancels the login -> we’re running denied(); or the user succeeds-> we’re running succeed();

In the function succeed, we extract the token out of the URL.

So now the function loginWithFacebook() receives the token. So we can add the following code:

loginWithFacebook() async{

String result = await Navigator.push(

context,

MaterialPageRoute(

builder: (context) => CustomWebView(

selectedUrl:

'https://www.facebook.com/dialog/oauth?client_id=$your_client_id&redirect_uri=$your_redirect_url&response_type=token&scope=email,public_profile,',

),

maintainState: true), if (result != null) {

try {

final facebookAuthCred =

FacebookAuthProvider.getCredential(accessToken: result);

final user =

await firebaseAuth.signInWithCredential(facebookAuthCred);

} catch (e) {}

}

);}

So now we have an acces token and we’re signed in.

Thanks for reading!