Jump to content

Troubles with header for authentication, CORS, and Options


Go to solution Solved by Jacques1,

Recommended Posts

I am using a header for authentication of an api.  If the header is not included, I send back a 401 code.

    $key = $request->getHeaderLine('X-GreenBean-Key');
    if (empty($key)) {
        $error=\MyApp\ErrorResponse::missingKey();
        return $response->withJson($error[0], $error[1]);
    }

Problem is my server is being hit twice, the first time without the header, and thus the client never attempts the second request.

 

The request is cross-domain, and thus I added the header name to Access-Control-Allow-Headers.

 

Below is my test scripts documenting what appears to be happening.

 

What am I doing wrong???

 

 

ajax.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Testing</title>  
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.js" type="text/javascript"></script>
        <script type="text/javascript">
            $(function(){
                $.ajax({
                    type:'GET',
                    url:'http://example.com/ajax',
                    headers: {"X-Greenbean-Key": "main_key"}
                })
            });
        </script>
    </head>

    <body></body>
</html>

ajax.php

<?php
require __DIR__.'/../vendor/autoload.php';
$logger = new \Monolog\Logger('my_logger');
$file_handler = new \Monolog\Handler\StreamHandler("../logs/testing.log");
$logger->pushHandler($file_handler);

$logger->addInfo('Server Hit.  Header: '.$_SERVER['HTTP_X_GREENBEAN_KEY']);

testing.log (for Monolog)

[2016-10-03 05:25:14] my_logger.INFO: Server Hit.  Header:  [] []
[2016-10-03 05:25:14] my_logger.INFO: Server Hit.  Header: main_key [] []

log (apache)

192.168.1.1 - - [03/Oct/2016:05:25:14 -0700] "OPTIONS /ajax.php HTTP/1.1" 200 134 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0 FirePHP/0.7.4"
192.168.1.1 - - [03/Oct/2016:05:25:14 -0700] "GET /ajax.php HTTP/1.1" 200 - "http://dd.badobe.com/ajax.html" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0 FirePHP/0.7.4"

 

httpd.conf

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/src/public
    <Directory "/var/www/src/public">
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
        RewriteEngine On
        Header set Access-Control-Allow-Origin "*"
        Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
        Header set Access-Control-Allow-Headers "X-Greenbean-Key, Origin, X-Requested-With, Content-Type, Accept"
    </Directory>
</VirtualHost>
  • Solution

When you set custom HTTP headers, the client has to preflight to determine whether the actual request will be valid. This is the OPTIONS request you're seeing in the log. When you respond with a 401 code, the client assumes that the test has failed and will not send the actual request.

 

To fix the problem, exclude OPTIONS requests from the header check so that the client will get a 200 response.

Edited by Jacques1
  • Like 1

Thank you!

 

Should an OPTIONS request always positively?  For instance, should every PHP script which responds to HTTP requests have the following few lines?

<?php
if ($_SERVER['REQUEST_METHOD']==='OPTIONS') {
    http_response_code(200);
    exit;
}

// remaining code goes here....

EDIT.  Or should apache/etc or php.ini be set up so it never gets to PHP?

Edited by NotionCommotion

When the client makes a preflight OPTIONS request, you need to respond with Access-Control-Allow-Origin, Access-Control-Request-Method (only if you're using more than GET and POST) and Access-Control-Allow-Headers. When the client makes the actual request, you need to respond with Access-Control-Allow-Origin.

 

Right now, it seems you allow CORS for absolute everything. That's a very bad idea, because the same-origin policy exists for a reason. You need to allow CORS for individual resources (hence the name). So if a particular PHP script should be accessible from other domains, that's when you enable CORS for this script.

 

Probably the most natural approach is to set the headers within the script. If you insist on doing it with the webserver, you need to apply the headers on a per-resource basis. In any case, skipping script execution in case of an OPTIONS request is extremely confusing, so, no, I wouldn't do that.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.