Hackernoon logoHow to Build a Simple API in Rust (Part 3) by@ncribt

How to Build a Simple API in Rust (Part 3)

NARUHODO Hacker Noon profile picture


Software engineer during the week and apprentice blogger during the weekend. I like JS and Rust. 🤓

Welcome to the third and last part of the guide on how to build an API in Rust!

To follow this guide, you will need to have the code from the second part. If you haven’t checked it out yet, please do!

This time I will explain how to protect the

POST /items
endpoint with a JWT (JSON Web Token).

Again, I will put all the code in the same file (



To be able to follow the guide, you will need to have Rust and Cargo installed. You will also need to have MongoDB running. If you need help installing MongoDB, I’ve covered this in the second part of the guide.

Set up the environment

We need to add a new environment variable in the 

file. Open the 
file, then under the
add a new variable named
and set the value to anything you like.

Add the new dependency

We need to add one new dependency

- a crate that allows us to encode, decode and validate JWTs.

Update the

file with the new dependency. The updated dependencies should be like this:

tide = "0.16"
async-std = { version = "1", features = ["attributes"] }
serde = { version = "1", features = ["derive"] }
dotenv = "0.15"
mongodb = { version = "1", features = ["async-std-runtime"], default-features = false }
jsonwebtoken = "7"

Let’s code

We need to make some modifications to the code. First, update the imports with the following:

use async_std::stream::StreamExt;
use dotenv::dotenv;
use jsonwebtoken;
use mongodb::bson::doc;
use serde::{Deserialize, Serialize};
use std::{env, future::Future, pin::Pin};
use tide::{Body, Next, Request, Response, StatusCode};

These are all the module items we will use in this walk-through.

We need to create a new struct that defines the payload of the JWT. I will not be adding anything in the payload, so it will just be an empty struct.

Add the following somewhere in the


#[derive(Serialize, Deserialize)]
struct TokenClaims {}

Now that we have the

we need to write the middleware function. Add the following in the

fn auth_middleware<'a>(
  req: Request<State>,
  next: Next<'a, State>,
) -> Pin<Box<dyn Future<Output = tide::Result> + Send + 'a>> {
  return Box::pin(async {
    // Retrieve the "Authorization" header from the request
    let authorization_header = req.header("Authorization");

    // Check that the "Authorization" header is not missing
    // if it is missing, respond with 401
    let authorization_header = match authorization_header {
      Some(h) => h.as_str(),
      None => {
        return Ok(Response::new(StatusCode::Unauthorized));

    // Attempt to remove the "Bearer " prefix
    // if it does not start with "Bearer " respond with 401
    let token = match authorization_header.strip_prefix("Bearer ") {
      Some(t) => t,
      None => {
        return Ok(Response::new(StatusCode::Unauthorized));

    // Retrieve the "JWT_SECRET" environment variable
    let secret = env::var("JWT_SECRET").unwrap();

    // Decode the JWT
    let token = jsonwebtoken::decode::<TokenClaims>(
      // Do not require the "exp" claim in the token payload
      &jsonwebtoken::Validation {
        validate_exp: false,

    // If there was an error when decoding the token respond with 401
    if token.is_err() {
      return Ok(Response::new(StatusCode::Unauthorized));

    // The request is authorized, proceed with the next controller
    return Ok(next.run(req).await);

I’ve added comments to explain what’s going on.

To summarize, the middleware checks that there is an Authorization header in the request. It then tries to get the JWT from the header. Finally using the

crate, it attempts to decode the JWT. If there is any error during the process, the function responds with a 401 HTTP status code for Unauthorized. Otherwise the request is authorized and the middleware runs the next controller in the chain.

We have to change the main function to use this new middleware, update the POST

route like this:


Let’s test it out! Start the server with the following command:

cargo run

If you try to send a POST request on

you should get a 401 status code.

You need to generate a JWT with the secret you’ve set up in the .env file. An easy way to do this is to head over to jwt.io, change the payload to an empty JSON object {} and replace the default secret with yours. You can then copy the token.

Before sending the request, make sure to add an Authorization header with the following value

. Of course, replace
with the actual token.

Now if you try to send the

request again, you should get a 200 status code!


That’s it! This is the end of the tutorial. I hope it was helpful. If you noticed any errors or something that could be improved, please let me know!

You can find the full example of this walk-through on GitHub: https://github.com/ncribt/rust-api-example-part-3.

Previously published on https://naruhodo.dev/build-an-api-in-rust-part-3/.

NARUHODO Hacker Noon profile picture
by NARUHODO @ncribt. Software engineer during the week and apprentice blogger during the weekend. I like JS and Rust. 🤓Read my stories


Join Hacker Noon

Create your free account to unlock your custom reading experience.