Matthew Coates
Matthew Coates

Reputation: 43

Cannot override CORS headers in Slim Framework

I am using Slim v3 with the CORS middleware at https://github.com/tuupola/cors-middleware to handle CORS headers. Everything works, however I now need to be able to modify the Access-Control-Allow-Origin header based on who a user is logging in as. I have another middleware that executes after the CORS middleware to do user verification, and I was hoping that from within this middleware I could just add $response = $response->withHeader('Access-Control-Allow-Origin', $userdomain) and it would keep the rest of the CORS headers set by the previous middleware, but override that one. However, this doesn’t seem to happen. No matter where this middleware executes, the CORS headers are always the ones defined by the CORS middleware.

The current setup looks like this:

$app->add(new \Internal\OAuth\Middleware($this->getDBs()));

$app->add(new \Tuupola\Middleware\Cors([
    "origin" => ['*'],
    "methods" => ['GET', 'POST', 'PUT', 'OPTIONS', 'DELETE'],
    "headers.allow" => ['', 'Authorization', 'Content-Type', 'Content-Length', 'Origin', 'Accept'],
    "credentials" => true,
    "cache" => 100
]));

The \Internal\OAuth\Middleware __invoke looks like this:

public function __invoke($req, $res, $next) {
    //do authentication stuff
    $userdomain = 'http://blahblahblah';
    $res = $res->withHeader('Access-Control-Allow-Origin', $userdomain);
    return $next($req, $res);
}

Upvotes: 1

Views: 2456

Answers (2)

Ivan Dudarev
Ivan Dudarev

Reputation: 216

Try it:

index.php:

<?php

$app = new \Slim\App();

$app->add(new \Internal\OAuth\Middleware());

$app->get('/', function(\Psr\Http\Message\ServerRequestInterface $req, \Psr\Http\Message\ResponseInterface $res, $args) {
    $res->getBody()->write(json_encode(['url' => $req->getUri()->__toString(), 'args'=>$args]));
    return $res->withHeader('content-type', 'application/json');
});

$app->run();

src/Internal/OAuth/Middleware.php

<?php

namespace Internal\OAuth;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Middleware
{

    /**
     * @param ServerRequestInterface $req
     * @param ResponseInterface $res
     * @param callable $next
     * @return ResponseInterface
     */
    public function __invoke($req, $res, $next) {
        //do authentication stuff
        $options = [
            "origin" => ['http://blahblahblah'],
            "methods" => ['GET', 'POST', 'PUT', 'OPTIONS', 'DELETE'],
            "headers.allow" => ['', 'Authorization', 'Content-Type', 'Content-Length', 'Origin', 'Accept'],
            "credentials" => true,
            "cache" => 100
        ];
        $cors = new \Tuupola\Middleware\CorsMiddleware($options);
        $handler = new Handler($res, $next);
        $res = $cors->process($req, $handler);
        return $res;
    }
}

src/Internal/OAuth/Handler.php

<?php

namespace Internal\OAuth;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class Handler implements RequestHandlerInterface
{

    protected $callable;

    protected $response;

    public function __construct(ResponseInterface $response, callable $callable)
    {
        $this->callable = $callable;
        $this->response = $response;
    }

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $handler = $this->callable;
        return $handler($request, $this->response);
    }
}

Tests:

1.

curl "http://localhost:8088" --request OPTIONS --include --header "Origin: http://disallowed-host" --header "Access-Control-Request-Method: PUT"

HTTP/1.1 401 Unauthorized
Host: localhost:8088
Date: Tue, 04 Dec 2018 13:19:14 +0700
Connection: close
Content-Length: 0

2.

curl "http://localhost:8088" --request OPTIONS --include --header "Origin: http://blahblahblah" --header "Access-Control-Request-Method: PUT"

HTTP/1.1 200 OK
Host: localhost:8088
Date: Tue, 04 Dec 2018 13:19:04 +0700
Connection: close
Access-Control-Allow-Origin: http://blahblahblah
Access-Control-Allow-Credentials: true
Vary: Origin
Access-Control-Max-Age: 100
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS, DELETE
Content-Length: 0

Upvotes: 0

Ivan Dudarev
Ivan Dudarev

Reputation: 216

In the middleware you need to add a header AFTER the handler

<?php

namespase \Internal\OAuth;

class Middleware
{
    public function __invoke($req, $res, $next) {
        //do authentication stuff
        $userdomain = 'http://blahblahblah';
        $res = $next($req, $res);
        return $res->withHeader('Access-Control-Allow-Origin', $userdomain);
    }
}

Upvotes: 2

Related Questions