Securing Actix Rust APIs with API key

Abhinav Yadav
Intelliconnect Engineering
3 min readDec 15, 2021
Photo by Franck on Unsplash

In this article, we are going to look at some ways we can secure our API, especially with an API key.

We are going to use the actix-web framework in this article. Actix-web is `A powerful, pragmatic, and extremely fast web framework for Rust`.

We are going to look at three ways to secure our API

  • Cross-origin requests (CORS)
  • API key (we are going to implement this)
  • JSON web tokens (we are going to talk about it since there are already a lot of tutorials available for it)

You can find the code for this project is at GitHub.

Setup

cargo.toml file

//cargo.toml
[dependencies]
redis = {version = "0.21.4", features = ["tokio-comp"]}
actix-web = "4.0.0-beta.11"
rand = "0.8.4"
serde = {version = "1.0.130", features = ["derive"]}
serde_json = "1.0.71"
actix-web-httpauth = "0.6.0-beta.3"
actix-cors = "0.6.0-beta.3"

We are going to use Redis for storing our API keys. Rust provides a crate to interact with Redis, we are also going to use it with a tokio-comp feature for async runtime.

Actix-web-httpauth crate for creating authentication middleware. It makes it easy to create an auth middleware.

Actix-cors crate for CORS implementation.

Rand crate for generating random 10 digit API key.

Serde_json and serde crate for JSON interaction.

Securing API with CORS

we use CORS so that our API can only be accessed by selected domains. Actix-web makes it really easy to use CORS. It provides an actix_cors crate, which we can use as middleware.

Securing API with API key

code for this is at GitHub.

We will run a redis instance locally for storing API key. We will allow any origin since it is only for testing purpose. Furthermore, we will have a /create route for creating API keys. We will have the API routes which we want to protect as a service at route /api/{apikey} and wrap the API key auth middleware inside the service.

Our main function will look like this

we can store some data with API key in redis. I’m using a hash map structure to store organization name and authorization level, in rust it will look like this

#[derive(Serialize, Deserialize, Clone, Debug)]
struct Details {
org: String,
auth_level: usize,
}

We will create a validator function for the authentication middleware.

In the middleware, we are checking if the key is present in the database and if it’s available then we attach the data to the request and if not then we send an unauthorized response.

Let’s create the function for /create endpoint

here we are generating a random 10 digit API key, if it already exists then we generate another key. Then we store it in redis and send the API key as a JSON response.

Let’s create the /api/{apikey}/details route to get details saved for that key

like above, we can use web::ReqData<_> extractor in any route if we want to verify API key data.

Note :- we have to send a request with a dummy bearer token, since we are using actix-web-httpauth crate, or you can create a middleware from scratch.

Testing the API key code

run the project with

//start the redis server first and then
cargo run

if we send the POST request at 127.0.0.1:8000/create with JSON body

{
"org": "intelliconnect_tech",
"auth_level": 1
}

we will get a response like

{
"api_key": 5572139051
}

Then we can verify the API key by POST request to localhost:8000/api/5572139050/details with a dummy bearer token. We get the above data back.

Securing API with JWT tokens

there are lots of tutorials about implementing JWT tokens in actix-web. We can improve our security by using both API key and JWT token in the same API. Like, we can use API key to identify the organizations and JWT tokens for individual users.

Conclusion

Thanks for reading, and hope that this article helped someone. You can access code at GitHub.

--

--