rust 32 lines · 7 steps

Configuring CORS on an Axum Router

How to build an Axum router that applies a tuned CORS policy across its JSON API routes.

Explained by highlit
1use std::time::Duration;
2 
3use axum::{
4 http::{header, HeaderValue, Method},
5 routing::{get, post},
6 Json, Router,
7};
8use serde_json::{json, Value};
9use tower_http::cors::CorsLayer;
10 
11pub fn app() -> Router {
12 let cors = CorsLayer::new()
13 .allow_origin("https://app.example.com".parse::<HeaderValue>().unwrap())
14 .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
15 .allow_headers([header::AUTHORIZATION, header::CONTENT_TYPE])
16 .expose_headers([header::CONTENT_DISPOSITION])
17 .allow_credentials(true)
18 .max_age(Duration::from_secs(3600));
19 
20 Router::new()
21 .route("/api/profile", get(profile))
22 .route("/api/sessions", post(create_session))
23 .layer(cors)
24}
25 
26async fn profile() -> Json<Value> {
27 Json(json!({ "id": 42, "name": "Ada Lovelace" }))
28}
29 
30async fn create_session() -> Json<Value> {
31 Json(json!({ "token": "eyJhbGciOi...", "expires_in": 3600 }))
32}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A CORS layer must explicitly whitelist origins, methods, and headers rather than defaulting to permissive.
  2. 2Tower middleware applied with `.layer` wraps every route on the router uniformly.
  3. 3`allow_credentials(true)` requires a concrete origin — wildcards are rejected by browsers when credentials are sent.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Configuring CORS on an Axum Router — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code