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

Issues passing authentication cookies on Android #2009

Closed
FKruegerCofinpro opened this issue Feb 2, 2024 · 1 comment
Closed

Issues passing authentication cookies on Android #2009

FKruegerCofinpro opened this issue Feb 2, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@FKruegerCofinpro
Copy link

FKruegerCofinpro commented Feb 2, 2024

Environment

Technology Version
Flutter version 3.16.8
Plugin version ^6.0.0
Android version All Android devices -> minSdk 19

Description

In my Flutter app I try to authenticate the user for the transition between my app and my web app via setting the oauth accessToken and refreshToken as cookies. The approaches I tried were to implement this using the CookieManager and also by executing JavaScript in the "initialUserScripts". Both lead to the same issue. (See expected and current behaviour)

Also I am printing the cookies after I set them and they seem to be present.

Approach using CookieManager:

class WebViewDetailScreenArguments extends Equatable {
  final String title;
  final String uri;
  final bool isServiceBaseUri;

  const WebViewDetailScreenArguments({
    required this.uri,
    this.title = '',
    this.isServiceBaseUri = false,
  });

  @override
  bool get stringify => true;

  @override
  List<Object> get props => [title, uri, isServiceBaseUri];
}

class WebViewDetailScreenWrapperProvider extends StatelessWidget {
  final WebViewDetailScreenArguments arguments;

  const WebViewDetailScreenWrapperProvider({super.key, required this.arguments});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) =>
          WebviewCubit()..initWithAuth(path: arguments.uri, isServiceBaseUri: arguments.isServiceBaseUri),
      child: WebViewDetailScreen(
        title: arguments.title,
      ),
    );
  }
}

class WebViewDetailScreen extends StatefulWidget {
  final String title;

  const WebViewDetailScreen({
    super.key,
    required this.title,
  });

  @override
  State<WebViewDetailScreen> createState() => _WebViewDetailScreenState();
}

class _WebViewDetailScreenState extends State<WebViewDetailScreen> {
  @override
  Widget build(BuildContext context) {
    final GlobalKey webViewKey = GlobalKey();
    CookieManager _cookieManager = CookieManager.instance();

    final InAppWebViewSettings settings = InAppWebViewSettings(
      isInspectable: kDebugMode,
      thirdPartyCookiesEnabled: true,
      javaScriptEnabled: true,
      sharedCookiesEnabled: true,
    );

    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: TitleAppBar(
        isBackEnabled: true,
        isDarkActionBar: false,
        centerItem: Text(
          widget.title,
          style: context.textStyles.h5.semiBold.onContainer,
        ),
        onBackPressedCallback: () => Navigator.pop(context),
        leadingText: context.i18n.tooltipBackText,
        tooltipBackText: context.i18n.tooltipBackText,
        componentsConfig: context.componentStyles,
        assetConfig: context.assets,
      ),
      body: BlocBuilder<WebviewCubit, WebviewState>(
        builder: (context, state) {
          if (state is WebviewLoaded) {
            return InAppWebView(
              key: webViewKey,
              initialUrlRequest: URLRequest(url: WebUri(state.uri), httpShouldHandleCookies: true),
              initialSettings: settings,
              onWebViewCreated: (InAppWebViewController controller) async {
                /// Deleting the cookies or not here does not make a difference
                await _cookieManager.deleteCookies(url: WebUri(state.uri));

                await _cookieManager.setCookie(
                    url: WebUri(state.uri),
                    name: 'accessToken',
                    domain: WebUri(state.uri).host, /// I tried hardcoding all URIs and domains with no luck
                    isSecure: true,
                    value: state.accessToken);
                await _cookieManager.setCookie(
                    url: WebUri(state.uri),
                    domain: WebUri(state.uri).host,
                    name: 'refreshToken',
                    isSecure: true,
                    value: state.refreshToken);
                await _cookieManager.setCookie(
                    url: WebUri(state.logoutUri),
                    domain: WebUri(state.uri).host,
                    name: 'logoutRedirectUri',
                    isSecure: true,
                    value: state.refreshToken);

                final accessCookie = await _cookieManager.getCookie(url: WebUri(state.uri), name: 'accessToken');
                final refreshCookie = await _cookieManager.getCookie(url: WebUri(state.uri), name: 'refreshToken');
                print(accessCookie);
                print(refreshCookie);
              },
            );
          } else if (state is WebviewFailure) {
            return Placeholder();
          } else {
            return AppBackgroundContainer(
              colorConfig: context.colorsWatch,
              child: Center(
                child: CircularProgressIndicator(),
              ),
            );
          }
        },
      ),
    );
  }
}

Approach using JavaScript:

class WebViewDetailScreenArguments extends Equatable {
  final String title;
  final String uri;
  final bool isServiceBaseUri;

  const WebViewDetailScreenArguments({
    required this.uri,
    this.title = '',
    this.isServiceBaseUri = false,
  });

  @override
  bool get stringify => true;

  @override
  List<Object> get props => [title, uri, isServiceBaseUri];
}

class WebViewDetailScreenWrapperProvider extends StatelessWidget {
  final WebViewDetailScreenArguments arguments;

  const WebViewDetailScreenWrapperProvider(
      {super.key, required this.arguments});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => WebviewCubit()
        ..initWithAuth(
            path: arguments.uri, isServiceBaseUri: arguments.isServiceBaseUri),
      child: WebViewDetailScreen(
        title: arguments.title,
      ),
    );
  }
}

class WebViewDetailScreen extends StatefulWidget {
  final String title;

  const WebViewDetailScreen({
    super.key,
    required this.title,
  });

  @override
  State<WebViewDetailScreen> createState() => _WebViewDetailScreenState();
}

class _WebViewDetailScreenState extends State<WebViewDetailScreen> {
  @override
  Widget build(BuildContext context) {
    final GlobalKey webViewKey = GlobalKey();

    InAppWebViewSettings settings = InAppWebViewSettings(
      isInspectable: kDebugMode,
      thirdPartyCookiesEnabled: true,
      javaScriptEnabled: true,
      sharedCookiesEnabled: true,
    );

    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: TitleAppBar(
        isBackEnabled: true,
        isDarkActionBar: false,
        centerItem: Text(
          widget.title,
          style: context.textStyles.h5.semiBold.onContainer,
        ),
        onBackPressedCallback: () => Navigator.pop(context),
        leadingText: context.i18n.tooltipBackText,
        tooltipBackText: context.i18n.tooltipBackText,
        componentsConfig: context.componentStyles,
        assetConfig: context.assets,
      ),
      body: BlocBuilder<WebviewCubit, WebviewState>(
        builder: (context, state) {
          if (state is WebviewLoaded) {
            return InAppWebView(
              key: webViewKey,
              initialUrlRequest: URLRequest(
                  url: WebUri(state.uri), httpShouldHandleCookies: true),
              initialSettings: settings,
              initialUserScripts: UnmodifiableListView<UserScript>([
                UserScript(
                    source:
                        'document.cookie="accessToken=${state.accessToken}";',
                    injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START),
                UserScript(
                    source:
                        'document.cookie="refreshToken=${state.refreshToken}";',
                    injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START),
                UserScript(
                    source:
                        'document.cookie="logoutRedirectUri=${state.logoutUri}";',
                    injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START),
                UserScript(
                    source: 'console.log(document.cookie)";',
                    injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START),
              ]),
            );
          } else if (state is WebviewFailure) {
            return Placeholder();
          } else {
            return AppBackgroundContainer(
              colorConfig: context.colorsWatch,
              child: Center(
                child: CircularProgressIndicator(),
              ),
            );
          }
        },
      ),
    );
  }
}

Expected behavior:
The user is authenticated when entering the Angular frontend via the InAppWebView both on iOS and Android devices.

Current behavior:
The user is authenticated when entering the Angular frontend via the InAppWebView on iOS devices.
On Android devices, the user is prompted to log in.

I hope you can help. Thanks!

@FKruegerCofinpro FKruegerCofinpro added the bug Something isn't working label Feb 2, 2024
Copy link

github-actions bot commented Feb 2, 2024

👋 @FKruegerCofinpro

NOTE: This comment is auto-generated.

Are you sure you have already searched for the same problem?

Some people open new issues but they didn't search for something similar or for the same issue. Please, search for it using the GitHub issue search box or on the official inappwebview.dev website, or, also, using Google, StackOverflow, etc. before posting a new one. You may already find an answer to your problem!

If this is really a new issue, then thank you for raising it. I will investigate it and get back to you as soon as possible. Please, make sure you have given me as much context as possible! Also, if you didn't already, post a code example that can replicate this issue.

In the meantime, you can already search for some possible solutions online! Because this plugin uses native WebView, you can search online for the same issue adding android WebView [MY ERROR HERE] or ios WKWebView [MY ERROR HERE] keywords.

Following these steps can save you, me, and other people a lot of time, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant