Dev-DhanushKumar
Dev-DhanushKumar

Reputation: 35

How to Set Cookies in GraphQL Rust WARP

Now I'm writing an authentication code using Rust WARP with the GraphQL API. In the below code, I'm running, but I don't know how to set the cookie in the browser. Here, this GraphQL code is working like a gateway. It will send the request to the backend server that evaluates the user email and password to generate the JWT token, and that token will be sent to the gateway. Here, we will set that token in the client.rs file perform_login_rpc function. Here is the code below.

src/main.rs

use juniper_warp::{make_graphql_filter, playground_filter};
use warp::Filter;

mod graphql;

mod auth_capnp {
    include!(concat!(env!("OUT_DIR"), "/auth_capnp.rs"));
}


#[tokio::main]
async fn main() {
    // Create a new schema
    let schema = std::sync::Arc::new(graphql::schema::create_schema());

    // Create a warp filter for the GraphQL schema
    let graphql_filter = make_graphql_filter(schema, warp::any().map(|| ()).boxed());

    // Serve the GraphQL schema at /graphql
    let graphql_route = warp::path("graphql").and(warp::post()).and(graphql_filter);

    // Serve the GraphQL playground at /playground
    let playground_route =
        warp::path("playground").and(playground_filter("/graphql", Some("/subscriptions")));

    println!("Listening on http://localhost:3030/graphql");

    // Start the server
    warp::serve(graphql_route.or(playground_route))
        .run(([0, 0, 0, 0], 3030))
        .await;
}

src/graphql/schema.rs

use crate::graphql::resolvers::auth::AuthRoot;
use crate::graphql::resolvers::query::QueryRoot;
use juniper::{EmptySubscription, RootNode};

pub type Schema = RootNode<'static, QueryRoot, AuthRoot, EmptySubscription<()>>;

pub fn create_schema() -> Schema {
    Schema::new(QueryRoot, AuthRoot, EmptySubscription::<()>::new())
}

src/graphql/resolvers/query.rs

use juniper::{FieldResult, GraphQLObject};

#[derive(GraphQLObject)]
pub struct Item {
    pub id: i32,
    pub name: String,
}

pub struct QueryRoot;

#[juniper::graphql_object]
impl QueryRoot {
    pub fn hello() -> FieldResult<String> {
        Ok("Hello, world!".to_string())
    }

    pub fn items() -> FieldResult<Vec<Item>> {
        let items = vec![
            Item {
                id: 1,
                name: "Item 1".to_string(),
            },
            Item {
                id: 2,
                name: "Item 2".to_string(),
            },
        ];
        Ok(items)
    }
}

src/graphql/resolvers/auth.rs

use juniper::{FieldResult, GraphQLObject};
use crate::graphql::resolvers::client_service::client::{perform_login_rpc,perform_register_rpc};

#[derive(GraphQLObject)]
pub struct AuthResponse {
    pub jwttoken: String,
}
#[derive(GraphQLObject)]
pub struct RegisterResponse {
    pub status: bool,
}

pub struct AuthRoot;

#[juniper::graphql_object]
impl AuthRoot {
    pub async fn login(username: String, password: String) -> FieldResult<AuthResponse> {
        println!("Here from AuthRoot!");
        perform_login_rpc(&username, &password).await
    }

    pub async fn register(name: String, email: String, password: String) -> FieldResult<RegisterResponse> {
        perform_register_rpc(&name, &email, &password).await
    }
}

src/graphql/resolvers/client_service/client.rs

use crate::{auth_capnp::user_auth, graphql::resolvers::auth::{AuthResponse, RegisterResponse}};
use capnp_rpc::{
    rpc_twoparty_capnp::{self, Side},
    twoparty::VatNetwork, RpcSystem,
};
use futures::{task::LocalSpawnExt, AsyncReadExt, FutureExt};
use juniper::FieldResult;


pub async  fn perform_register_rpc(name: &str, email: &str, password: &str) -> FieldResult<RegisterResponse> {
    let mut exec = futures::executor::LocalPool::new();
    let spawner = exec.spawner();
    exec.run_until(async move {
        let mut rpc_system: RpcSystem<Side> = get_rpc_system().await.expect("REASON");
        let auth_service: user_auth::Client =
            rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server);
        let _ = spawner
            .spawn_local(Box::pin(rpc_system.map(|_| ())));

        let mut request = auth_service.register_request();
        let mut binding = request.get().init_request();

        binding.set_name(&name.to_string());
        binding.set_email(&email.to_string());
        binding.set_password(&password.to_string());

        let response = request.send().promise.await?;
        let is_successful = response.get().expect("Reader Not Working");
        let res = is_successful.get_status();

        if res {
            Ok(RegisterResponse{
                status: res
            })
        } else {
            Err("Register Failed!".into())
        }
    })
}


pub async fn perform_login_rpc(username: &str, password: &str) -> FieldResult<AuthResponse> {
    let mut exec = futures::executor::LocalPool::new();
    let spawner = exec.spawner();
    exec.run_until(async move {
        let mut rpc_system: RpcSystem<Side> = get_rpc_system().await.expect("REASON");
        let auth_service: user_auth::Client =
            rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server);
        let _ = spawner
            .spawn_local(Box::pin(rpc_system.map(|_| ())));
            
        // Initiate request
        let mut request = auth_service.login_request();
        let mut binding = request.get().init_request();
        binding.set_email(&username.to_string());
        binding.set_password(&password.to_string());
        // request.get().set_username(&username.to_string());
        // request.get().set_password(&password.to_string());

        let response = request.send().promise.await?;
        let is_successful = response.get().expect("Token Not Get");
        let token = is_successful.get_token()?.to_string().expect("String error");

        if !token.is_empty() {
            Ok(AuthResponse{
                jwttoken: token,
            })
        } else {
            Err("Login Failed!".into())
        }
    })
}


async fn get_rpc_system() -> Result<RpcSystem<Side>, String> {
    let stream = async_std::net::TcpStream::connect("127.0.0.1:4000")
        .await
        .map_err(|e| e.to_string())?;

    stream.set_nodelay(true)
    .map_err(|e| e.to_string())?;

    let (reader, writer) = stream.split();
    let network = Box::new(
        VatNetwork::new(reader, writer, Side::Client, Default::default())
    );

    Ok(RpcSystem::new(network, None))
}

"In this file, we'll implement the logic to send a request to our backend authentication server. Upon successful authentication, the server will provide a JWT token. We'll then use either the warp or cookie crate to securely store this token as a cookie on the client's side."

Upvotes: 0

Views: 54

Answers (0)

Related Questions