Access-Control-Allow-Origin: * allows any website to access your resources. Always specify exact origins in production.
ESP8266WebServer is a web server library for ESP8266 microcontrollers in Arduino projects. It's commonly used to create REST APIs and web interfaces for IoT devices. This guide shows how to add CORS headers to your ESP8266 HTTP responses.
Note: These examples work with the ESP8266WebServer library included in the ESP8266 Arduino Core. For ESP32, use the similar WebServer library with the same approach.
Allow requests from a specific origin:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
void handleRequest() {
// Set CORS headers for specific origin
server.sendHeader("Access-Control-Allow-Origin", "https://example.com");
server.sendHeader("Vary", "Origin");
// Send response
server.send(200, "application/json", "{\"message\":\"CORS enabled\"}");
}
void setup() {
// Connect to WiFi
WiFi.begin("your-ssid", "your-password");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// Define routes
server.on("/api/data", HTTP_GET, handleRequest);
// Start server
server.begin();
}
void loop() {
server.handleClient();
}
To allow multiple specific origins (issue #146):
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
// List of allowed origins
const char* allowedOrigins[] = {
"https://example.com",
"https://app.example.com"
};
const int numAllowedOrigins = 2;
// Function to check if origin is allowed
bool isOriginAllowed(String origin) {
for (int i = 0; i < numAllowedOrigins; i++) {
if (origin == allowedOrigins[i]) {
return true;
}
}
return false;
}
void handleRequest() {
// Get origin from request header
String origin = server.header("Origin");
// Validate and set CORS headers
if (isOriginAllowed(origin)) {
server.sendHeader("Access-Control-Allow-Origin", origin);
server.sendHeader("Vary", "Origin");
}
// Send response
server.send(200, "application/json", "{\"message\":\"CORS enabled\"}");
}
void setup() {
WiFi.begin("your-ssid", "your-password");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
server.on("/api/data", HTTP_GET, handleRequest);
server.begin();
}
void loop() {
server.handleClient();
}
For APIs that use custom headers or methods like PUT/DELETE:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
const char* allowedOrigins[] = {
"https://example.com",
"https://app.example.com"
};
const int numAllowedOrigins = 2;
bool isOriginAllowed(String origin) {
for (int i = 0; i < numAllowedOrigins; i++) {
if (origin == allowedOrigins[i]) {
return true;
}
}
return false;
}
// Handle preflight OPTIONS request
void handleOptions() {
String origin = server.header("Origin");
if (isOriginAllowed(origin)) {
server.sendHeader("Access-Control-Allow-Origin", origin);
server.sendHeader("Vary", "Origin");
}
server.sendHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
server.sendHeader("Access-Control-Max-Age", "86400");
server.send(204);
}
// Handle actual request
void handleRequest() {
String origin = server.header("Origin");
if (isOriginAllowed(origin)) {
server.sendHeader("Access-Control-Allow-Origin", origin);
server.sendHeader("Vary", "Origin");
}
server.send(200, "application/json", "{\"message\":\"CORS enabled\"}");
}
void setup() {
WiFi.begin("your-ssid", "your-password");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// Register OPTIONS handler for preflight
server.on("/api/data", HTTP_OPTIONS, handleOptions);
// Register actual request handlers
server.on("/api/data", HTTP_GET, handleRequest);
server.on("/api/data", HTTP_POST, handleRequest);
server.on("/api/data", HTTP_PUT, handleRequest);
server.on("/api/data", HTTP_DELETE, handleRequest);
server.begin();
}
void loop() {
server.handleClient();
}
Create reusable functions to simplify CORS across multiple endpoints:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
const char* allowedOrigins[] = {
"https://example.com",
"https://app.example.com"
};
const int numAllowedOrigins = 2;
bool isOriginAllowed(String origin) {
for (int i = 0; i < numAllowedOrigins; i++) {
if (origin == allowedOrigins[i]) {
return true;
}
}
return false;
}
// Reusable function to add CORS headers
void addCorsHeaders() {
String origin = server.header("Origin");
if (isOriginAllowed(origin)) {
server.sendHeader("Access-Control-Allow-Origin", origin);
server.sendHeader("Vary", "Origin");
}
}
// Reusable function to handle preflight
void handleCorsOptions() {
addCorsHeaders();
server.sendHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
server.sendHeader("Access-Control-Max-Age", "86400");
server.send(204);
}
// Example endpoint handlers
void handleData() {
addCorsHeaders();
server.send(200, "application/json", "{\"data\":\"value\"}");
}
void handleStatus() {
addCorsHeaders();
server.send(200, "application/json", "{\"status\":\"ok\"}");
}
void setup() {
WiFi.begin("your-ssid", "your-password");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// Register OPTIONS handler for all endpoints
server.on("/api/data", HTTP_OPTIONS, handleCorsOptions);
server.on("/api/status", HTTP_OPTIONS, handleCorsOptions);
// Register endpoint handlers
server.on("/api/data", HTTP_GET, handleData);
server.on("/api/status", HTTP_GET, handleStatus);
server.begin();
}
void loop() {
server.handleClient();
}
Only use for completely public resources:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
void handleOptions() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.sendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "Content-Type");
server.sendHeader("Access-Control-Max-Age", "86400");
server.send(204);
}
void handleRequest() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "application/json", "{\"message\":\"Public API\"}");
}
void setup() {
WiFi.begin("your-ssid", "your-password");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
server.on("/api/public", HTTP_OPTIONS, handleOptions);
server.on("/api/public", HTTP_GET, handleRequest);
server.begin();
}
void loop() {
server.handleClient();
}
server.sendHeader() before server.send() to ensure headers are included in the response.server.sendHeader("Access-Control-Allow-Credentials", "true");ESP8266WebServer with WebServer and #include <WebServer.h>. The API is nearly identical.Tip: For complex web applications on ESP8266, consider using ESPAsyncWebServer instead, which provides better performance and built-in CORS support through its AsyncCallbackWebHandler.
For comprehensive testing instructions including curl commands, browser DevTools usage, and troubleshooting common CORS errors, see the CORS Testing Guide.
The content on this site stays fresh thanks to help from users like you! If you have suggestions or would like to contribute, fork us on GitHub.
Save 39% on CORS in Action with promotional code hossainco at manning.com/hossain