Rust Warp: Use Cookie for Authorization
Tags: rust, warp
Published: 2021-12-31 06:57:00

---
title: Rust Warp: Use Cookie for Authorization
published: true
date: 2021-11-24 13:11:48 UTC
tags: Rust,Warp
canonical_url: http://coderscat.com/rust-warp-use-cookie-for-authorization/
---


[Warp](https://github.com/seanmonstar/warp) is a composable, web server in Rust. It's code is very small and focus on speed.

The fundamental building block of `warp` is the `Filter`, they can be combined and composed to express rich requirements on requests.

But it's actually not easy to use if you are not familiar with it's concept, and the type system will also scare some beginners.

For example, I actually spend some time to figure out how to use Cookie for authorization. 


Suppose we have defined a Struct to represent the User: 

```Rust

#[derive(Debug, Deserialize)]
pub struct User {
    username: String,
    password: String,
}
```

And we have a logic to authorize whether the login request has a valid username and password, the detail implementation depends on your code:

```Rust
pub fn verify_user(user: &User) -> bool {
	....
}
```


The question is how to set a Cookie in response and how to verify each request after authorization. 

### Set a cookie 
When a user send login request and passed the authorization, we use `reply` with `with_header` to set a cookie to store a token, which will be used for later requests:

```Rust
 let login = warp::path!("api" / "login")
        .and(warp::post())
        .and(warp::body::json())
        .map(|user: auth::User| {
            if auth::verify_user(&user) {
                let token = auth::gen_token();
                warp::reply::with_header(
                    token.clone(),
                    "set-cookie",
                    format!("token={}; Path=/; HttpOnly; Max-Age=1209600", token),
                )
                .into_response()
            } else {
                warp::reply::with_status("failed", http::StatusCode::UNAUTHORIZED).into_response()
            }
        });
    let routes = routes.or(login);
```


### Use cookie for Authorization
To authorize request, we need to implement a `filter` in Warp, and use it like this, here we use `Filter::untuple_one` to unroll nested tuple layers from extractions.

```Rust
  let verify = warp::path!("api" / "verify")
        .and(warp::get())
        .and(auth_validation())
        .untuple_one()
        .map(|| warp::reply::reply().into_response());
    let routes = routes.or(verify);
```

And the `auth_validation` will call another built-in filter `warp::cookie` to extract the `token` from request header:

```Rust
struct Unauthorized;

impl reject::Reject for Unauthorized {}

fn auth_validation() -> impl Filter<Extract = ((),), Error = Rejection> + Copy {
    warp::cookie::<String>("token").and_then(|token: String| async move {
        println!("token: {}", token);
        if let Some(true) = auth::verify_token(&token) {
            Ok(())
        } else {
            Err(warp::reject::custom(Unauthorized))
        }
    })
}

```

### Some thoughts
Even I have spent some time writing code in Rust, I still need to learn some new concepts or some details in a Web framework such as Warp. From my experience, there are some unnatural part for users who used to some other programming languages. For example, the return type of a filter: 

```Rust
impl Filter<Extract = ((),), Error = Rejection> + Copy
```

It's just not so easy to say what this mean? And why we need to call `untuple_one` with the filter? 

I know we must obey the rules of type system, and we need to add more annotations when writing Rust code, it's just not so easy for learning as other programming languages. 

Even so, I'm still having fun with it for it bringing some new things for programming.