Question

I am building a PHP Api that will allow a mobile app to talk to it. The app is more of a tech demo at the moment to test technology and ideas.

To secure the app requests, certain things will need authentication.

So let's take the following for example:

$('form').submit(function(e){

    e.preventDefault();

    var form = $(this);

    var data = form.serialize();

    $.ajax({
        type: 'POST',
        url: form.attr('action'),
        data: data,
        success: function(response){

            // show success message or error depending on authentication

        },
        error: function(a,b,c) {

        }   
    });

});

I'm also using header('Access-Control-Allow-Origin: *'); to allow the app to talk to it, and the wildcard because it's only a test at the moment. However in a real life situation I wouldn't have a domain because it would be running from a mobile device rather than another domain (PhoneGap most probably).

I've looked around on the net and come across HTTP Authorization but can't get my head around it no matter how many docs I read.

An example of it would be something like:

Authorization: TRUEREST username=john&password=test&apikey=247b5a2f72df375279573f2746686daa

and I've thought about passing said data like so based on what I've seen in jQuery docs:

data: {
    username: 'john',
    password: 'test',
    apiKey: '247b5a2f72df375279573f2746686daa'
},
headers: {
    Authorization: "TRUEREST"
},

I can check that the username and password exists in the DB first before sending back the JSON and also perhaps checking the Api key in the same way.. but I'm not understanding the TRUEREST part at all or what it can offer to the code?

UPDATE

I have been trying the following in my jQuery code:

headers: {
                            Authorization: "TRUEREST",
                            username: 'dave',
                            password: 'test',
                            apiKey: 'qwe123'    
                        },

and then in my PHP:

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Authorization,Content-type,username,password,apiKey');

if($_SERVER['REQUEST_METHOD'] == 'POST')
{


    $headers = $_SERVER['HTTP_AUTHORIZATION'];
    $parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);

    header('Content-type: application/json');
    print json_encode($parts);

    exit;

The returned JSON is just TRUEREST! None of the others are being seen by PHP. But if I look in the web inspector they are being sent fine. But noticed that two types of requests are being made POST and OPTIONS.

Any ideas?

I'm basing these updates on what I have read here: https://github.com/kvz/cakephp-rest-plugin/blob/master/Controller/Component/RestComponent.php#L516

Was it helpful?

Solution

First off, you don't need to worry about cross-domain restrictions in a PhoneGap app.

Remember that it's the browser that enforces same-origin rules. The only involvement your server might have is when a page on a different domain tries to make a XHR request for something on your server; the CORS specification outlines how that's handled. If you respond with appropriate Access-Control-Allow-Origin headers, the XHR request is allowed unrestricted.

So in PhoneGap, there is no browser enforcing same-origin rules – only PhoneGap's configuration (which you control). PhoneGap allows you to specify which domains (or all) your app will have access to. Once whitelisted, your code will be able to make XHR requests to those domains with no restrictions.

The only sticky thing is that when using jQuery to make XHR requests, it will try to convert your requests into JSONP, incorrectly assuming that it must work around same-origin rules.

To fix this, you can force jQuery to always use XHR:

$.ajaxSetup({crossDomain:false});

Regarding Authorization, that's fairly simple. A client sends the string literal Basic, a space, and then the username, a colon, and the password base64-encoded.

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Decoding the base64 data yields Aladdin:open sesame.


Based on the jQuery snippet you added, your HTTP request looks like this:

POST /form.php HTTP/1.1
Host: example.com
X-Requested-With: XmlHttpRequest
Authorization: TRUEREST
username: dave
password: test
apiKey: qwe123
...

It should be obvious why $_SERVER['HTTP_AUTHORIZATION'] only contains TRUEREST: the other items are completely separate (and invalid) headers. Try:

headers: {
    Authorization: 'X-My-API ' + $.param({
        username: 'dave',
        password: 'test',
        apiKey: 'qwe123'
    })
}

Now your request will look like this:

POST /form.php HTTP/1.1
Host: example.com
X-Requested-With: XmlHttpRequest
Authorization: X-My-API username=dave&password=test&apiKey=qwe123
...
  • $.param serializes an object into a URL-encoded query string.
  • You should probably consider base64 encoding the authorization data, just like HTTP Basic auth. This will ensure that only [A-Za-z0-9+/=] (printable) characters are in the HTTP headers, potentially avoiding security problems.
  • I'm not entirely clear on the RFC's requirements, but by convention, non-standard extensions to HTTP are usually prefixed with X-. Since your authorization scheme is non-standard, you should do the same.
  • The OPTIONS request you are seeing is CORS at work. If you specify custom headers in a cross-domain XHR request, the browser first checks with the server to see if it sends Access-Control-Allow-Origin headers in response (the "preflight request"). Only if it does will the browser send the actual POST with data.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top