Rust cors warning

Hello, i have this warning on all requests. While everything works i can't get rid of it.
I can't understand cors (i seen documentation still can't, it's to random from me), i'm not a frontend developer but need to make some website now.

Cross-Origin Request Warning: The Same Origin Policy will disallow reading the remote resource at http://127.0.0.1:3000/users?per_page=10&page=1&filter= soon. (Reason: When the Access-Control-Allow-Headers is *, the Authorization header is not covered. To include the Authorization header, it must be explicitly listed in CORS header Access-Control-Allow-Headers).

use crate::models::Claims;
use axum::{
    http::{Request, StatusCode},
    middleware::Next,
    response::IntoResponse,
};
use jsonwebtoken::{decode, DecodingKey, Validation};

pub async fn auth_middleware<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse {
    //disable auth on login
    if req.uri().path() == "/login" {
        return next.run(req).await;
    }

    let auth_header = req.headers().get("Authorization");
    if let Some(auth_header) = auth_header {
        if let Ok(token) = auth_header.to_str() {
            let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
            let validation = Validation::default();
            match decode::<Claims>(
                token.trim_start_matches("Bearer "),
                &DecodingKey::from_secret(secret.as_bytes()),
                &validation,
            ) {
                Ok(_) => {
                    return next.run(req).await;
                }
                Err(_) => {
                    return (StatusCode::UNAUTHORIZED, "Invalid or expired token").into_response();
                }
            }
        }
    }
    (StatusCode::UNAUTHORIZED, "Authorization header missing").into_response()
}

my main.rs file:

use axum::{
    middleware,
    routing::{delete, get, post, put},
    Router,
};
use dotenv::dotenv;
use listenfd::ListenFd;
use std::net::TcpListener;
use tower_http::cors::{Any, CorsLayer};

mod auth_middleware;
mod db;
mod handlers;
mod models;

#[tokio::main]
async fn main() {
    dotenv().ok();
    let pool = db::init_pool().await;
    let mut listenfd = ListenFd::from_env();
    let std_listener = match listenfd.take_tcp_listener(0).unwrap() {
        Some(listener) => listener,
        None => TcpListener::bind("127.0.0.1:3000").unwrap(),
    };

    let cors = CorsLayer::new()
        .allow_origin(Any)
        .allow_methods([
            axum::http::Method::GET,
            axum::http::Method::POST,
            axum::http::Method::PUT,
            axum::http::Method::DELETE,
        ])
        .allow_headers(Any);

    let app = Router::new()
        .route("/login", post(handlers::login::login))
        .route("/users", get(handlers::users::get_users))
        .route("/users/:id", get(handlers::users::get_user))
        .route("/users/:id", put(handlers::users::update_user))
        .route("/users/:id", delete(handlers::users::delete_user))
        .route("/profiles", get(handlers::profiles::get_profiles))
        .route("/profiles/:id", get(handlers::profiles::get_profile))
        .route("/profiles", post(handlers::profiles::create_profile))
        .route("/profiles/:id", put(handlers::profiles::update_profile))
        .layer(middleware::from_fn(auth_middleware::auth_middleware))
        .layer(cors)
        .with_state(pool);

    let addr = std_listener.local_addr().unwrap();
    println!("Listening on {}", addr);
    axum::Server::from_tcp(std_listener)
        .unwrap()
        .serve(app.into_make_service())
        .await
        .unwrap();
}

my api.ts in vue 3 maybe will be of any help

import axios from "axios";
import { errorInterceptor } from "./interceptors";

const API_HEADERS = {
  "X-Requested-With": "XMLHttpRequest",
  "Access-Control-Allow-Origin": "*",
};

const API = axios.create({
  baseURL: `${import.meta.env.VITE_APP_API_URL}`,
  headers: API_HEADERS,
  timeout: 30000,
});

errorInterceptor(API);

export default API;

export * from "./helpers";

The error message appears to be saying that when you initialise CorsLayer, you need to pass all the request header names you intent to use to .allow_headers([...]), rather than using Any (that is, *). That should be Authorization and X-Requested-With. You should also remove "Access-Control-Allow-Origin": "*" from API_HEADERS, since it’s only a response header.

I’m not sure if that will solve everything, but any new error message should give you the next step.

1 Like

now nothing works, no idea what is wrong with this :confused:

use axum::http::header::{ACCEPT, AUTHORIZATION};
use axum::{
    middleware,
    routing::{delete, get, post, put},
    Router,
};
use dotenv::dotenv;
use listenfd::ListenFd;
use std::net::TcpListener;
use tower_http::cors::{Any, CorsLayer};
mod auth_middleware;
mod db;
mod handlers;
mod models;

#[tokio::main]
async fn main() {
    dotenv().ok();
    let pool = db::init_pool().await;
    let mut listenfd = ListenFd::from_env();
    let std_listener = match listenfd.take_tcp_listener(0).unwrap() {
        Some(listener) => listener,
        None => TcpListener::bind("127.0.0.1:3000").unwrap(),
    };

    let cors = CorsLayer::new()
        .allow_origin(Any)
        .allow_methods([
            axum::http::Method::GET,
            axum::http::Method::POST,
            axum::http::Method::PUT,
            axum::http::Method::DELETE,
            axum::http::Method::OPTIONS,
        ])
        .allow_headers([AUTHORIZATION, ACCEPT]);

    let app = Router::new()
        .route("/login", post(handlers::login::login))
        .route("/users", get(handlers::users::get_users))
        .route("/users/:id", get(handlers::users::get_user))
        .route("/users/:id", put(handlers::users::update_user))
        .route("/users/:id", delete(handlers::users::delete_user))
        .route("/profiles", get(handlers::profiles::get_profiles))
        .route("/profiles/:id", get(handlers::profiles::get_profile))
        .route("/profiles", post(handlers::profiles::create_profile))
        .route("/profiles/:id", put(handlers::profiles::update_profile))
        .layer(middleware::from_fn(auth_middleware::auth_middleware))
        .layer(cors)
        .with_state(pool);

    let addr = std_listener.local_addr().unwrap();
    println!("Listening on {}", addr);
    axum::Server::from_tcp(std_listener)
        .unwrap()
        .serve(app.into_make_service())
        .await
        .unwrap();
}

As carey told you, try removing the "Access-Control-Allow-Origin" header from your request you make from your vue frontend, it doesn't have a meaning when it is part of the headers of a http request:

import axios from "axios";
import { errorInterceptor } from "./interceptors";

const API_HEADERS = {
  "X-Requested-With": "XMLHttpRequest",
- "Access-Control-Allow-Origin": "*",
};

const API = axios.create({
  baseURL: `${import.meta.env.VITE_APP_API_URL}`,
  headers: API_HEADERS,
  timeout: 30000,
});

errorInterceptor(API);

export default API;

export * from "./helpers";

I did that still got warning, adding proposed code in corsLayer makes error that i attached on screenshot.

You probably don’t need X-Requested-With in your application. In the past, it’s been useful for preventing some kinds of CSRF by explicitly checking for it in the server code, but you can use fetch metadata request headers for that now; and it triggers a CORS preflight request, but so does including an Authorization header. Given that, and since Access-Control-Allow-Origin is not a valid request header, I’d create the Axios client like:

const API = axios.create({
  baseURL: import.meta.env.VITE_APP_API_URL,
  timeout: 30000,
});

Then you will need to add all the other headers that Axios sets to your Rust code. This is at least Authorization, but may include Accept as you’ve done, and maybe also Content-Type, and x-xsrf-token if you use Axios’ CSRF-prevention support. The error message displayed in your browser should change to show what value is missing.

Aside: For my work, I have not had to think about setting CORS response headers, or even supporting OPTIONS preflight requests, since it’s important to prevent unexpected cross-site requests. Our applications serve the HTML and JavaScript from the same server as the APIs, so nothing counts as CORS.

1 Like

Yea removing headers did not break anything, i did copy it from some template i found.
I used to do everything in laravel (php framework) where frontend and backend is in the same project and cors where never a problem. I'm only bothering with separate frontend now since there are way better component libraries in typescipt than php.

I managed to fix it. No more errors/warning! Thx for help

use axum::{
    middleware,
    routing::{delete, get, post, put},
    Router,
};
use dotenv::dotenv;
use listenfd::ListenFd;
use std::net::TcpListener;
use tower_http::cors::{Any, CorsLayer};

mod auth_middleware;
mod db;
mod handlers;
mod models;

#[tokio::main]
async fn main() {
    dotenv().ok();
    let pool = db::init_pool().await;
    let mut listenfd = ListenFd::from_env();
    let std_listener = match listenfd.take_tcp_listener(0).unwrap() {
        Some(listener) => listener,
        None => TcpListener::bind("127.0.0.1:3000").unwrap(),
    };

    let cors = CorsLayer::new()
        .allow_methods([
            axum::http::Method::GET,
            axum::http::Method::POST,
            axum::http::Method::PUT,
            axum::http::Method::DELETE,
        ])
        .allow_origin(Any)
        .allow_headers([
            axum::http::header::CONTENT_TYPE,
            axum::http::header::AUTHORIZATION,
        ]);

    let app = Router::new()
        .route("/login", post(handlers::login::login))
        .route("/users", get(handlers::users::get_users))
        .route("/users/:id", get(handlers::users::get_user))
        .route("/users/:id", put(handlers::users::update_user))
        .route("/users/:id", delete(handlers::users::delete_user))
        .route("/profiles", get(handlers::profiles::get_profiles))
        .route("/profiles/:id", get(handlers::profiles::get_profile))
        .route("/profiles", post(handlers::profiles::create_profile))
        .route("/profiles/:id", put(handlers::profiles::update_profile))
        .layer(middleware::from_fn(auth_middleware::auth_middleware))
        .layer(cors)
        .with_state(pool);

    let addr = std_listener.local_addr().unwrap();
    println!("Listening on {}", addr);
    axum::Server::from_tcp(std_listener)
        .unwrap()
        .serve(app.into_make_service())
        .await
        .unwrap();
}