ThexXTURBOXx / flutter_web_auth_2

Flutter plugin for authenticating a user with a web service
https://pub.dev/packages/flutter_web_auth_2
MIT License
53 stars 54 forks source link

Can't get web auth to work with my own authentication server #43

Closed JPFrancoia closed 1 year ago

JPFrancoia commented 1 year ago

Describe the bug

I can't get the authentication to work for the web platform. The authentication works on Android

To Reproduce

I have my own authentication/backend service to authenticate my users. The service is written in Go. The authentication flow works like this:

The above works when the client is a simple html page that I serve from the /login.html endpoint of the backend. This html pages just contains a link that points to http://localhost:8080/auth/facebook.

I'm now trying to build a proper UI with Flutter. So far I have something like this:

import 'package:flutter/material.dart';
import 'package:social_login_buttons/social_login_buttons.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Test',
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatelessWidget {
  LoginPage({super.key});

  @override
  Widget build(BuildContext context) {

    return LayoutBuilder(builder: (context, constraints) {
      return Scaffold(
        body: SocialLoginButton(
          buttonType: SocialLoginButtonType.facebook,
          onPressed: () async {
            final result = await FlutterWebAuth2.authenticate(
                url: "http://localhost:8080/auth/facebook", callbackUrlScheme: "callback-scheme");

            print("result: $result");

          },
        ),
      );
    });
  }
}

On the server side, there are just 2 simple functions that are called. The Login function (behing the /auth/facebook endpoint), which creates a Oauth link that the client will need to follow to start the auth flow:

func Login(c *gin.Context) {
        ...
    url, err := gothic.GetAuthURL(c.Writer, c.Request)

    if err != nil {
        c.AbortWithError(http.StatusInternalServerError, err)
    }

    c.Redirect(http.StatusFound, url)
}

And the AuthCallback function, behind the /auth/callback endpoint. This endpoint serves the auth.html page from your doc

func AuthCallback(c *gin.Context) {
    user, err := gothic.CompleteUserAuth(c.Writer, c.Request)

        ...

    c.HTML(http.StatusOK, "auth.html", gin.H{})
    // c.Redirect(http.StatusFound, "callback-scheme://")  // This makes it work with Android
}

This setup works for Android when the backend redirects to callback-scheme://. However it doesn't work for the web platform: when I click the login button, another tab opens with Facebook, I can give permissions for my app, then I'm redirected to the auth.html page. The page is closed almost immediately (makes sense, since we're doing window.close() there). But this line in the flutter app is never executed:

            print("result: $result");

And obviously if it's not executed, I can't get the token back.

Expected behavior

The auth.html page should be able to send information back to the main app.

Device (please complete the following information!)

Additional context

Add any other context about the problem here.

Checklist

ThexXTURBOXx commented 1 year ago

Please try to run the example which works properly on my machine. If that also does not work, there might be something wrong with your setup

ThexXTURBOXx commented 1 year ago

Sorry, didn't mean to close this issue

JPFrancoia commented 1 year ago

Ok I got it to work, I was pretty much there, the only thing was to make the backend redirect to the auth.html from the app, and not serve this page directly from the backend:

    c.Redirect(http.StatusFound, "http://localhost:8081/auth.html")

Where 8081 is the port number where the flutter app is running.

One last thing, do you know if there is a way to tell the backend (so that would be while calling FlutterWebAuth2.authenticate) if the flutter app is running on a web platform or on Android?

ThexXTURBOXx commented 1 year ago

Very nice to hear! :)

About your question: I think there are multiple ways to do it. One of them would be to identify the current platform in your app and passing it to your backend using a query parameter or similar. Another possibility would be to analyse the browser that is currently used to get the web page, but that can be spoofed, so it might be a bit unreliable.

For the former suggestion, you might want to use e.g. Platform.isAndroid and kIsWeb as shown in the example