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

want an API can get webview cookie #518

Closed
awkj opened this issue Mar 6, 2022 · 23 comments · Fixed by #1394
Closed

want an API can get webview cookie #518

awkj opened this issue Mar 6, 2022 · 23 comments · Fixed by #1394

Comments

@awkj
Copy link

awkj commented Mar 6, 2022

Is your feature request related to a problem? Please describe.
I want use wry load a remote url, wait user login, and get cookie to use user cookie to call thrid-service api, so I need get cookie on user login sucesss.

Describe the solution you'd like

I use electron session to finish it, the sesion can give all webview cookies, cache, proxy setting...
but I can't found tauri have similar API

Describe alternatives you've considered
I found wry can preload script , I try init script and send event to main process, but the remote url will run 302 redict and callback , my init script will loss.

Would you assign yourself to implement this feature?

  • [ x ] No

Additional context
electron session : https://www.electronjs.org/docs/latest/api/session

@awkj awkj changed the title want an API similar to electron session want an API can get webview cookie Mar 6, 2022
@keiya01
Copy link
Member

keiya01 commented Jun 16, 2022

related to #444.

I think you can access non secure cookie from HTTP request by using custom protocol but can't get secure cookie.
Because wry is not supporting HTTPS request yet. See related issue for more details.

@keiya01
Copy link
Member

keiya01 commented Jun 22, 2022

Do we need to implement feature to access webview cookie even if secure cookie can not be handled?

@erguotou520
Copy link

This is useful.

@luxalpa
Copy link

luxalpa commented Mar 16, 2023

I need this one as well.

1 similar comment
@avrilko-go
Copy link

I need this one as well.

@FabianLars
Copy link
Member

please just tick the thumbs up button at the top instead of adding "+1" comments that will notify all users subscribed to this issue!

@ww-k
Copy link

ww-k commented Apr 7, 2023

@pokecheater
Copy link

pokecheater commented Jun 18, 2023

Hello :).
Hey is this still open?
I have exactly the same problem. We have an authentication server that renders a login mask. The client will open this webpage for login (tauri opens the external webpage and renders it). As soon as the user logins it set's a private cookie that can not be obtained by javascript and redirect to the webpages from tauri (localhost).

In another electron app we are using it already and it is quite simple to get the cookie then in the backend and handle all secure relevant authentication functions inside the electron backend. I want to implement the same in tauri. How can I achieve it if I have no possibility to obtain the cookie itself?

for example in electron I can obtain the cookies like this:
image

Thx in advance <3

@rnza0u
Copy link

rnza0u commented Aug 12, 2023

For those who absolutely want to read cookies from a window's browsing context, you can still do the following:

let window = WindowBuilder::new(
        app, // your AppHandle
        "some-window",
        WindowUrl::External("https://somewhere.com".parse().unwrap()),
    )
    .data_directory("/home/me/session-data") // pass custom path here
    .build()
    .expect("could not create window");

let cookies = std::fs::read_to_string("/home/me/session-data/cookies").expect("could not read cookies");

println!("{cookies}");

This code would display something like that:

somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_1      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_2      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_3      COOKIE_VALUE       None
... etc

I don't know what all the fields are but at least you can easily retrieve the name and value for each cookie.

It's a terrible solution but it works for me !

I believe the feature should really be available, just like in Electron.

@David-Kyrat
Copy link

I would really love this feature as well. Love the tauri "ecosystem" btw thanks for everything.

@github-project-automation github-project-automation bot moved this to 📬Proposal in Roadmap Sep 25, 2023
@Luna-CY
Copy link

Luna-CY commented Oct 13, 2023

Is there any progress on this issue?

@FabianLars
Copy link
Member

Is there any progress on this issue?

Not on our side at least, meaning no maintainer is actively working on it. No idea if there's a community member working on it but at least nobody reached out to us :)

@yetone
Copy link

yetone commented Dec 2, 2023

For those who absolutely want to read cookies from a window's browsing context, you can still do the following:

let window = WindowBuilder::new(
        app, // your AppHandle
        "some-window",
        WindowUrl::External("https://somewhere.com".parse().unwrap()),
    )
    .data_directory("/home/me/session-data") // pass custom path here
    .build()
    .expect("could not create window");

let cookies = std::fs::read_to_string("/home/me/session-data/cookies").expect("could not read cookies");

println!("{cookies}");

This code would display something like that:

somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_1      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_2      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_3      COOKIE_VALUE       None
... etc

I don't know what all the fields are but at least you can easily retrieve the name and value for each cookie.

It's a terrible solution but it works for me !

I believe the feature should really be available, just like in Electron.

It's quite strange, the contents of my data folder are empty.

@prabhupant
Copy link

For those who absolutely want to read cookies from a window's browsing context, you can still do the following:

let window = WindowBuilder::new(
        app, // your AppHandle
        "some-window",
        WindowUrl::External("https://somewhere.com".parse().unwrap()),
    )
    .data_directory("/home/me/session-data") // pass custom path here
    .build()
    .expect("could not create window");

let cookies = std::fs::read_to_string("/home/me/session-data/cookies").expect("could not read cookies");

println!("{cookies}");

This code would display something like that:

somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_1      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_2      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_3      COOKIE_VALUE       None
... etc

I don't know what all the fields are but at least you can easily retrieve the name and value for each cookie.
It's a terrible solution but it works for me !
I believe the feature should really be available, just like in Electron.

It's quite strange, the contents of my data folder are empty.

+1

I tried to do the same thing but the data folder never gets populated.

@pokecheater
Copy link

Is there any progress on the issue?
I want to fix my insecure workarounds on our auth server that I had to do in order to make it working with tauri. It really would make me sad to go back to electron for our applications...😢.

@pokecheater
Copy link

pokecheater commented Jan 16, 2024

For those who absolutely want to read cookies from a window's browsing context, you can still do the following:

let window = WindowBuilder::new(
        app, // your AppHandle
        "some-window",
        WindowUrl::External("https://somewhere.com".parse().unwrap()),
    )
    .data_directory("/home/me/session-data") // pass custom path here
    .build()
    .expect("could not create window");

let cookies = std::fs::read_to_string("/home/me/session-data/cookies").expect("could not read cookies");

println!("{cookies}");

This code would display something like that:

somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_1      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_2      COOKIE_VALUE       None
somewhere.com   FALSE   /       FALSE   1722097323      COOKIE_3      COOKIE_VALUE       None
... etc

I don't know what all the fields are but at least you can easily retrieve the name and value for each cookie.
It's a terrible solution but it works for me !
I believe the feature should really be available, just like in Electron.

It's quite strange, the contents of my data folder are empty.

Me neither.
I also tried to find the default path, since It would also be okay for me if I can use the default window from tauri.config.json. But I was not able to find where the default data_directory is. I used

    const appDataDirPath = await appDataDir();
    console.log("appDataDirPath", appDataDirPath);

on frontend side and it tells me a path that simply does not exist:

/Users/XXX/Library/Application Support/XXX-app.xyz/

I really don't get it. In another blog post I read that tauri does not preserve cookies for localhost domain when chrom or safari is used as web engine.

image

tauri-apps/tauri#2490

So is there really no workaround available for this issue?

I asked a half year ago and others even earlier, is there no solution to this issue?

Besides: I had tried the solution proposed by Hakhenaton. But the code gave me compilation errors. I needed to use a pathBuf object. str is not compatible with data_directory() method. Here is my adapted rust code:

tauri::Builder::default()
        .setup(|app| {
            let path_str = "/Users/xxx/session_data/cookies";
            let data_directory: PathBuf = PathBuf::from(path_str);
            let path_string: String = data_directory.to_string_lossy().to_string();
            let window = tauri::WindowBuilder::new(app, "label", tauri::WindowUrl::App("index.html".into()))
            .data_directory(data_directory)
            .build()?;

            // let cookies = std::fs::read_to_string(path_string).expect("could not read cookies");
            // println!("{cookies}");
            Ok(())
        })
        .manage(...)

The command for cookie reading always fails (I assume since the file does not exist, the cookie data does not get populated as yetone and prabhupant stateted), so I commented it out in my tests.

@pokecheater
Copy link

pokecheater commented Jan 16, 2024

Where are the cookies stored and how do I access them? If I know this, I can write my own get cookie handler on rust side.

@lucassilvas1
Copy link

lucassilvas1 commented Apr 13, 2024

The only way for a user to sign in to my app is through a remote URL which I do not control. Being able to extract cookies from the webview is the only way I could ever port my Electron app to Tauri.

@typed-sigterm
Copy link

It's somtimes possible to grab cookies indirectly by intercepting WebView network requests (Set-Cookie), but there seems to be no readily available implementation.

@lucassilvas1
Copy link

@Zihan-Hu Do you think it would be hard to implement cross-platform reliably?

@typed-sigterm
Copy link

@Zihan-Hu Do you think it would be hard to implement cross-platform reliably?

Sometimes it feels like herding cats and sometimes very easy 🤔 In my opinion, it depends on the tech stack you're using and your target user base.

@mastergyp
Copy link

Getting cookies by reading Chrome's cookie database on your computer. https://github.com/lei4519/extract-chrome-cookies

lucasfernog added a commit that referenced this issue Oct 21, 2024
* feat: add `WebView::cookies` and `WebView::cookies_for_url`

closes #518
ref: tauri-apps/tauri#11330

* cookies -> getCookies in android

* fix macos build

* fix gtk blocking

* document why we don't use wait_for_async_operation

* change file

* implement cookies_for_url on macOS

* fmt

* fix macos impl

* actually use interval

* make it faster

* remove matching on path

* Apply suggestions from code review

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>

* Apply suggestions from code review

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
@t348575
Copy link

t348575 commented Nov 5, 2024

I am using an alternative approach to grab cookies: Register a custom protocol for your window using register_uri_scheme_protocol, then just replace the custom scheme with http (s), send your request, extract cookie data from the response, and send the response back to the window.

Example implementation (with reqwest):

fn change_uri_scheme(uri: &tauri::http::Uri, new_scheme: &str) -> Result<tauri::http::Uri, tauri::http::Error> {
    let scheme = tauri::http::uri::Scheme::try_from(new_scheme)?;

    let path_and_query = uri.path_and_query().map(|pq| pq.as_str()).unwrap_or("");
    let new_uri = tauri::http::Uri::builder()
        .scheme(scheme)
        .authority(uri.authority().unwrap().as_str())
        .path_and_query(path_and_query)
        .build()?;

    Ok(new_uri)
}

fn convert_reqwest_to_http_response(reqwest_response: reqwest::blocking::Response) -> Result<(Response<Vec<u8>>, Option<String>), Box<dyn Error>> {
    let status = reqwest_response.status();
    let mut http_response = tauri::http::Response::builder()
        .status(status);

    let mut cookie_data = None;
    for (key, value) in reqwest_response.headers().iter() {
        if key.as_str() == "set-cookie" {
            cookie_data = Some(value.to_str().unwrap().to_string());
        }
        http_response = http_response.header(key, value);
    }

    let body = reqwest_response.bytes()?.to_vec();
    Ok((http_response.body(body)?, cookie_data))
}

fn main() {
    tauri::Builder::default()
        .register_uri_scheme_protocol("cookie", move |_ctx, mut request| {
            *request.uri_mut() = change_uri_scheme(request.uri(), "https").unwrap();

            let client = reqwest::blocking::Client::new();
            let reqwest_request = reqwest::blocking::Request::try_from(request).unwrap();

            let (response, cookie_data) = convert_reqwest_to_http_response(client.execute(reqwest_request).unwrap()).unwrap();
            // do whatever with cookie_data
            response
        })
        .setup(move |app| {
            let window = tauri::webview::WebviewWindowBuilder::new(app, "some-window", tauri::WebviewUrl::External("cookie://some-url-to-visit/".parse().unwrap()));
            let window = window.title("Some window").build().expect("could not create window");
            Ok(())
        }).run(tauri::generate_context!()).unwrap();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 📬Proposal
Development

Successfully merging a pull request may close this issue.