Access Control Headers For The WordPress REST API

Sending headers, including cross-origin (CORS) headers has changed a bit in version 2 of the WordPress REST API. Access control headers are sent by the function rest_send_cors_headers(), which is hooked to rest_pre_serve_request. You can easily change the headers by unhooking that function, and adding your own.

Below are some examples using access control headers, but really any type of header could be added here. That said, keep in mind that the class WP_REST_Response, which should be used for all responses, also gives you the ability to add headers. Any headers unique to a request should be set there.

/**
 * Use * for origin
 */
add_action( 'rest_api_init', function() {
    
	remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
	add_filter( 'rest_pre_serve_request', function( $value ) {
		header( 'Access-Control-Allow-Origin: *' );
		header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
		header( 'Access-Control-Allow-Credentials: true' );

		return $value;
		
	});
}, 15 );


/**
 * Only allow GET requests
 */
add_action( 'rest_api_init', function() {
    
	remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
	add_filter( 'rest_pre_serve_request', function( $value ) {
		$origin = get_http_origin();
		if ( $origin ) {
			header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
		}
		header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) );
		header( 'Access-Control-Allow-Methods: GET' );

		return $value;
		
	});
}, 15 );


/**
 * Only allow same origin
 */
add_action( 'rest_api_init', function() {

	remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
	add_filter( 'rest_pre_serve_request', function( $value ) {
		header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) );
		header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
		header( 'Access-Control-Allow-Credentials: true' );

		return $value;
		
	});
}, 15 );


/**
 * Only from certain origins
 */
add_action( 'rest_api_init', function() {

	remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
	add_filter( 'rest_pre_serve_request', function( $value ) {

		$origin = get_http_origin();
		if ( $origin && in_array( $origin, array(
				//define some origins!
			) ) ) {
			header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
			header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
			header( 'Access-Control-Allow-Credentials: true' );
		}

		return $value;
		
	});
}, 15 );


I have a plugin for setting CORS for GET requests and a plugin for setting CORS for ALL requests on Github.

8 Replies to “Access Control Headers For The WordPress REST API”

  1. Is this still working in 2017? It doesn’t work for me, I’m trying to access pagination, but `offset` isn’t publicly accessible

  2. If I implement CORS on my WordPress backend, what would my $http GET request look like? I keep hitting a 500 internal server error after adding one of your code samples and can’t figure out what’s going on.

    I added the code sample to class-wp-rest-response.php in wp-includes/rest-api; I’m new to WordPress so this may be completely incorrect.

  3. Many thanks for this! I’ve been trying to figure out how to get CORS headers to work.

    I was looking at the latest version of the plugin, and I don’t see ‘rest_pre_serve_request’ or ‘rest_send_cors_headers’. Do you know if they were removed? And, if so, can we now just do:

    add_action( 'rest_api_init', function() {
    header( 'Access-Control-Allow-Origin: *' );
    header( 'Access-Control-Allow-Methods: GET' );
    return $value;
    }, 15 );

    Also, is there any security risk for allowing all origins? I would think if we just limit the method to GET, is wouldn’t introduce any new risk.

    1. Those filters are in WordPress now, not the plugin:

      • rest_pre_serve_request filter is in /wp-includes/rest-api/class-wp-rest-server.php
      • rest_send_cors_headers function is in wp-includes/rest-api.php

      CORS Isn’t exactly a security thing, since origin is so easily spoofed. It’s more to tell browsers that are following the rules if you want them to allow other sites to use your resources or not.

Leave a Reply

Your email address will not be published. Required fields are marked *