Problems with creating request guard for jsonwebtoken in Rocket 0.5.0-rc.3

Hello! I want to create a request guard to check for a jsonwebtoken in a cookie on a rocket server, but I am running into strange issues...

This is my cargo.toml:

[package]
name = "bread"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dotenv = "0.15.0"
jsonwebtoken = "8.3.0"
mongodb = { version = "2.4.0", default-features = false, features = ["sync"] }
password-hash = "0.5.0"
rocket = { version = "0.5.0-rc.3", features = ["json"] }
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }
rust-argon2 = "1.0"
serde = "1.0.154"

This is my code:

use jsonwebtoken::{DecodingKey, EncodingKey, Validation};
use rocket::{
    data::Outcome,
    http::Status,
    request::{FromRequest, Request},
};
use serde::{Deserialize, Serialize};

pub const ENCODING_KEY: EncodingKey = EncodingKey::from_secret("SECRET".as_bytes());
pub const DECODING_KEY: DecodingKey = DecodingKey::from_secret("SECRET".as_bytes());

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub exp: usize,
    pub sub: String,
}

#[rocket::async_trait]
impl<'a> FromRequest<'a> for Claims {
    type Error = String;

    async fn from_request(request: &'a Request<'_>) -> Outcome<Self, Self::Error> {
        let cookie = request
            .cookies()
            .get("api-token")
            .map(|cookie| cookie.value());

        let token = match cookie {
            Some(encoded_token) => {
                jsonwebtoken::decode::<Claims>(encoded_token, &DECODING_KEY, &Validation::default())
                    .ok()
                    .map(|token| token.claims)
            }
            None => None,
        };

        match token {
            Some(valid_token) => Outcome::Success(valid_token),
            None => Outcome::Failure((
                Status::Unauthorized,
                "Invalid or missing API token!".to_string(),
            )),
        }
    }
}

From what I can see, it looks like the examples in the rocket documentation: FromRequest in rocket::request - Rust. However, this code yields the following errors:

error[E0106]: missing lifetime specifier
  --> src\api\token.rs:22:63
   |
22 |     async fn from_request(request: &'a Request<'_>) -> Outcome<Self, Self::Error> {
   |                                    ---------------            ^ expected named lifetime parameter
   |
   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
note: these named lifetimes are available to use
  --> src\api\token.rs:19:6
   |
19 | impl<'a> FromRequest<'a> for Claims {
   |      ^^
...
22 |     async fn from_request(request: &'a Request<'_>) -> Outcome<Self, Self::Error> {
   |     ^^^^^                                      ^^
help: consider using one of the available lifetimes here
   |
22 |     async fn from_request(request: &'a Request<'_>) -> Outcome<'lifetime, Self, Self::Error> {
   |                                                                ++++++++++

error[E0053]: method `from_request` has an incompatible type for trait
  --> src\api\token.rs:22:5
   |
22 |     async fn from_request(request: &'a Request<'_>) -> Outcome<Self, Self::Error> {
   |     ^^^^^
   |     |
   |     expected `()`, found struct `Data`
   |     help: change the output type to match the trait: `Pin<Box<(dyn std::future::Future<Output = Outcome<Claims, (Status, std::string::String), ()>> + std::marker::Send + 'async_trait)>>`
   |
   = note: expected signature `fn(&'a rocket::Request<'life0>) -> Pin<Box<(dyn std::future::Future<Output = Outcome<Claims, (Status, std::string::String), ()>> + std::marker::Send + 'async_trait)>>`
              found signature `fn(&'a rocket::Request<'life0>) -> Pin<Box<(dyn std::future::Future<Output = Outcome<Claims, (Status, std::string::String), rocket::Data<'static>>> + std::marker::Send + 'async_trait)>>`

Some errors have detailed explanations: E0053, E0106.
For more information about an error, try `rustc --explain E0053`.
error: could not compile `bread` due to 2 previous errors

The first error can be fixed by changing the function's signature to this:

async fn from_request(request: &'a Request<'_>) -> Outcome<'a, Self, Self::Error> 

But the other error still persists after that:

error[E0053]: method `from_request` has an incompatible type for trait
  --> src\api\token.rs:22:5
   |
22 |     async fn from_request(request: &'a Request<'_>) -> Outcome<'a, Self, Self::Error> {
   |     ^^^^^
   |     |
   |     expected `()`, found struct `Data`
   |     help: change the output type to match the trait: `Pin<Box<(dyn std::future::Future<Output = Outcome<Claims, (Status, std::string::String), ()>> + std::marker::Send + 'async_trait)>>`
   |
   = note: expected signature `fn(&'a rocket::Request<'life0>) -> Pin<Box<(dyn std::future::Future<Output = Outcome<Claims, (Status, std::string::String), ()>> + std::marker::Send + 'async_trait)>>`
              found signature `fn(&'a rocket::Request<'life0>) -> Pin<Box<(dyn std::future::Future<Output = Outcome<Claims, (Status, std::string::String), rocket::Data<'a>>> + std::marker::Send + 'async_trait)>>`

For more information about this error, try `rustc --explain E0053`.
error: could not compile `bread` due to previous error

What is causing this error? Where is this rocket::Data coming from and how can I make i into a ()? Any idea of how to fix it? I have been sitting with this trying lots of stuff for hours... For full context, all code is available here: GitHub - BurnyLlama/bread: Bread is a social media focusing in the mental health and privacy..

Thanks in advance,
BurnyLlama

You are importing rocket::data::Outcome, but you should be importing rocket::request::Outcome.

Oh my.... thank you! Can't believe I forgot to check something as basic as the imoorts....

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.