Async-graphql: Set cookie value inside of GraphQL mutation

Created on 15 Jan 2021  路  4Comments  路  Source: async-graphql/async-graphql

I've read through https://github.com/async-graphql/async-graphql/issues/370, but I think this doesn't apply when working with Rocket and their cookie implementation, as they also provide encrypted cookies that can't be used the same way as the solution provided in the linked issue.

Encrypted cookies are created and read by interacting with Rocket's cookie jar implementation (get_private, set_private). If I use the solution from the issue, I'd still set the cookies unencrypted.

I've tried to integrate it by myself, but the only solution I could come up with was to invoke the POST as normal. And instead of returning it directly, I check if the response was of from my login route and extract the needed data if that is the case. I then set the cookie and return the response after that from my route method:

#[rocket::post("/graphql", data = "<request>", format = "application/json", rank = 2)]
async fn post_graphql_request(
    schema: State<'_, Schema>,
    cookies: &CookieJar<'_>,
    request: Request,
) -> Response {
    let response: Response = request
        .execute(&schema)
        .instrument(tracing::debug_span!("graphql_post_request"))
        .await;

    match &response.0 {
        BatchResponse::Single(resp) => {
            // check that GraphQL body contains the JSON representation of the login route result.
            // If that is the case, proceed with setting the private cookie in the jar.
        }
        _ => {
            // this doesn't matter for the login route.
        }
    }

    response
}

It seems like I can't pass the CookieJar as a data to the scheme as it's just a reference. The lifetime would have to be static as far as I can tell (required from the data() function). Using <'a> doesn't seem to work :(

question

Most helpful comment

I haven't thought of a good way yet, but as a GraphQL library, these features should not be included.

All 4 comments

@sunli829 probably has a better perspective on this than me, but 2 possible approaches to try in the interim (I'm not overly familiar with Rocket, but I can theoretically guess how it would work)

  1. Use the Set-Cookie header, passing through HttpOnly and Secure, this is actually how I ended up doing it for #370 (and I'm fairly sure is what all the cookie implementations will desugar to anyway). It's up to the browser implementation to actually keep HttpOnly cookies away from javascript _at least from my understanding_. So "Set-Cookie": "key=value; HttpOnly; Secure; Expires=...". (although I must admit I'm still yet to find a way of making that approach play nice with the GraphQL playground for testing purposes - so let me know if you work that out).
  2. If you pull your own fork of the integration library, although there might be a nicer solution, at around this point in the code: https://github.com/async-graphql/async-graphql/blob/master/integrations/rocket/src/lib.rs#L178, you could probably parse the existing headers and choose to set them directly on the cookie jar there.

Solution one would definitely work. The key difference though to other web frameworks is that the private functions of the cookie jar actually encrypt and decrypt the cookies. I think to get the full functionality I'd have to tinker around with the integration itself.

I haven't thought of a good way yet, but as a GraphQL library, these features should not be included.

I haven't thought of a good way yet, but as a GraphQL library, these features should not be included.

Definitely not. However, I don't see any other way to make it work besides having it inside the integration. I'm still tinkering around with designs to see what fits the best.

Was this page helpful?
0 / 5 - 0 ratings