Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't authenticate request #16

Open
VittorioParagallo opened this issue Aug 25, 2020 · 5 comments
Open

Can't authenticate request #16

VittorioParagallo opened this issue Aug 25, 2020 · 5 comments

Comments

@VittorioParagallo
Copy link

Is it possible to add the possibility to add authorization header?
without it becomes useless in a secured environment :(
i've been looking all around last two days and it looks like this feature is missing in the original eventsource api, but there are some implementations with polyfill

@jonasbark
Copy link

What makes you think that it's not supported?
The connect method accepts a header argument:
https://github.com/stevenroose/dart-eventsource/blob/master/lib/eventsource.dart#L61

Though I'm not sure how well / if it works on the Web.

@VittorioParagallo
Copy link
Author

VittorioParagallo commented Oct 9, 2020 via email

@tnovoselec
Copy link

@VittorioParagallo Could you share your solution for Web? Having the same issue with Web implementation

@alexbvw
Copy link

alexbvw commented Feb 23, 2022

@VittorioParagallo can you please share how you managed to use Dio for SSE with authorization headers? - I am trying the same and it connects but doesn't stream the data

@VittorioParagallo
Copy link
Author

VittorioParagallo commented Aug 27, 2022

I uploaded the code in my repo.

I guess that taking my code and following these steps can you easily to the solution. (my repo is a fully working app)

At first add this js file to the web folder of your flutter project(it's the polyfill):
https://github.com/VittorioParagallo/swingcriminals_secretary/blob/master/web/eventsource.js
It's the javascript code that does the work done.

Then we need to call that javascript object from dart.
so i wrote all the needed code in the folder http_sse_tool

You can download the whole folder, it contains 5 files:

  • eventsource_commons.dart : groups the object needed by the other files
  • js_eventsource_polyfill.dart: it's a bridge class javascript<-> dart. It allows to instantiate the js object and call it's method.
  • eventsource_html.dart: wraps js_eventsource_polyfill.dart and exposes the sse functions so it is the class used for the web
  • eventsource_io.dart: wraps the package:restio/restio.dart file
  • eventsource_stub.dart: is the class with exactly the same methods of eventsource_html.dart and eventsource_io.dart. It is used as a stub to dinamically import the right class in case of web or app, here below i show you how.

Now that everything is set, is possible to develop the api, the one i did is rest_api_service.dart.
In that file you can see the import:

`import 'package:swingcriminals_secretary/http_sse_tool/eventsource_stub.dart'
    // ignore: uri_does_not_exist
       if (dart.library.html) 'package:swingcriminals_secretary/http_sse_tool/eventsource_html.dart'
    // ignore: uri_does_not_exist
       if (dart.library.io) 'package:swingcriminals_secretary/http_sse_tool/eventsource_io.dart';`

So the import dinamically loads the right file wether is a web app or not. That's why a stub with all unimplemented closures was needed.

In the same file you can see the normal get (baseUrl is the webserver and url is the right part endpoint):

`

 Future<dynamic> get(String url) async {
 print("Called RestApiService:get($url)");
var responseJson;
try {
        final response = await http.get(baseUrl + url,
        headers: await AuthService().getRestHeaderWithToken());
        responseJson = _returnResponse(response);
     } on SocketException {
     throw FetchDataException('No Internet connection');
     }
return responseJson; 
 }

`

(_returnResponse check if it has data or error status, check at the end of the file).

This uses the conventional 'package:http/http.dart' and returns just one result.
While the method sseGet:

  Future<EventSource> sseGet(String url) async {
     print("Called RestApiService:sseGet($url)");
    try {
      EventSource eventSource = await EventSource.connect(baseUrl + url,
          headers: await AuthService().getSseHeaderWithToken());
      return eventSource;
    } on SocketException {
      throw FetchDataException('No Internet connection');
    }
  }

Works the same way, but returns the EventSource object which is a stream, and continues to stream data till it's closed.
You can check th method .getSseHeaderWithToken()) in the file auth_service.dart.

  Future<Map<String, String>> getSseHeaderWithToken() async {
    FirebaseUser user = await firebase.currentUser();
    var token = (await user.getIdToken()).token;
    return {
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      'Accept': 'text/event-stream',
      'Authorization': 'Bearer $token',
    };
  }

It just prepares the header with the bearer token.

I hope it helps. I just tested again the code and it works great!
Let me know your feedbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants