1

I am trying to build a simple API to allow a client to send me data over HTTPS. I created a class that will take a username/password then it does a database look up. If the user is found then it issues a token. Then the token will be send back to the requester via HTTP header.

Once a username, password and a token sent back then the script reads the data sent from the client via $_POST request and processes it.

The challenge that I am having is sending the token to the requester via cURL and receiving the USERNAME, PASSWORD & TOKEN from the HTTP header correctly.

My question is how can I correctly send the token via HTTP header in the generateToken() method? Also how can I read the HTTP headers once the request is made?

Below is my class: api.php file

<?php
require('../classes/connection.php');

class api {

    private $user_name;
    private $user_password;
    private $user_token;
    private $db;
    private $keepAlive = 120; //2 minutes = 120 seconds
    private $authorizes = false;
    private $token = '';
    private $ch;
    private $user_ready = false;

    function api($database, $server){

        //establish a database connection
        $this->db = new connection($database, $server);
        $this->ch = curl_init();

        //read user_name, password, token from the header and set it
        if(isset($_SERVER['API-User-Name']))
            $this->user_name = $_SERVER['API-User-Name'];

        if(isset($_SERVER['API-User-Password']))
            $this->user_password = $_SERVER['API-User-Password'];

        if(isset($_SERVER['API-User-Token']))
            $this->user_token = $_SERVER['API-User-Token'];

        //check if the user is allowed
        if(  $this->authenticateAccess() === true  ){
            $this->authorizes = true;

            //ensure the token is valid otherwise generate a new token
            if(     $this->isValidToken()   )
                $this->user_ready = true;
            else 
                $this->generateToken();
        }
    }

    //return weather to process the send data
    public function isUserReady(){
        return $this->user_ready;
    }

    //return weather the user is authorized
    private function isAutherized(){
        return $this->authorizes;
    }

    //return the set token
    private function getToken(){
        return $this->token;
    }

    //check if the requester is authorized to access the system
    private function authenticateAccess(){

        //unauthorized old session
        $this->unautherizeExpiredTokens();

        if( $this->ch === false) 
            return false;

        if( empty($this->user_name)  || empty($this->user_password)  )
            return false;

        //ensure HTTPS is used  
        if( !isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') 
            return false;
         //read the user information                
         $get_user = $this->db->getDataSet('SELECT ip_addreses, user_password, token_expires_on, current_token
                                            FROM api_users
                                            WHERE user_name = ?
                                            LIMIT 1', array($this->user_name));

         if( count($get_user) != 1)
            return false;

         $data = $get_user[0];

         //remove bad values if any
         $ip_addreses = preg_replace("/[^0-9,.]/", "", $data['ip_addreses']);

         $allowed_ips = explode(',', $ip_addreses);

        //ensure the IP address is allowed
        if( !isset($_SERVER['REMOTE_ADDR']) || !in_array($_SERVER['REMOTE_ADDR'], $allowed_ips) )
            return false;

        //check if the password is valid    
        if( password_verify($this->password, $data['user_password'] ) )
            return true;
        else        
            return false;
    }


    //check if the token is valid
    private function isValidToken(){

        if(     !$this->isAutherized()  )
            return false;

        //unauthorized old session
        $this->unautherizeExpiredTokens();


        if( empty($this->user_token) )
            return false;

         $get_user = $this->db->getDataSet('SELECT token_expires_on, current_token
                                            FROM api_users
                                            WHERE user_name = ? AND current_token = ?
                                            LIMIT 1', array($this->user_name, $this->user_token ));

         if( count($get_user) != 1)
            return false;

        $data = $get_user[0];

        if( empty($data['token_expires_on']) || $data['current_token'] != $this->user_token )
            return false;

        //make sure that the token is not expired
        if( !empty($data['token_expires_on']) && time() > $data['token_expires_on'])
            return false;   

    }

    //generate a new token
    private function generateToken(){
            //generate a token          
            $token = md5(uniqid(mt_rand(), true));
            //set expiration date for this token
            $expire_on = time() + $this->keepAlive;

            //Save the new token in the database with expiration time = $this->keepAlive seconds
            $update = $this->db->processQuery('UPDATE api_users
                                               SET current_ip = ?,
                                               current_token = ?,
                                               token_expites_on = ?
                                               WHERE user_name = ?', array($_SERVER['REMOTE_ADDR'], $token, $expire_on ));
            //if the token is saved in the database then send the new token via cURL header.                                   
            if($update){
                //set the token as a header value and then sent it back to the requester.
                $this->token = $token;
                $curl_header = array();
                $curl_header[] = 'API-User-Token: ' . $token;
                curl_setopt($this->ch, CURLOPT_HEADER, true);
                curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_header);

                return $token;
            } else
                return false;   
    }


    //remove old tokens
    private function unautherizeExpiredTokens(){

        $this->db->processQuery('UPDATE api_users
                                 SET current_ip = NULL,
                                 current_token = NULL,
                                 token_expites_on = NULL
                                 WHERE token_expites_on IS NOT NULL AND token_expites_on <= ?', array( time() ) );  

    }

}

?>

And to use this class I would do the following form the API access link. Once I figure out how to ready the http data then there will be no need to pass the $username and $password to the class instead it will be ready in the class from the header.

Therefore, the access.php file will look like the following

include('api.php');


$request = new api('database_name','serverIPaddress');


if( $request->isUserReady() ){
    //process transaction all transactions
    $_POST['notes'];  //// take the data validated it and then insert into the database

    echo 'Bingo!';

} else {
    echo 'You are not authorized to use this API';
}

?>

To use this API the client will have to call it like so client.php file will looks like this:

<?php

$curl_header = array();
$curl_header[] = 'API-User-Name: test';
$curl_header[] = 'API-User-Password: password';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mydomainname.com/api/access.php");
//curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_header);
$result = curl_exec($ch);


print_r($result);
curl_close($ch);


?>
0

1 Answer 1

2

Just use CURLOPT_HTTPHEADER:

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  'X-THING_ONE: abcdefghijklmnopqrstuvwxyz',
  'X-THING_TWO: 12345678910'
));

I prefer to set the header as an array outside of the curl_setopt like this:

$curl_headers = array();

$curl_headers[] = 'X-THING_ONE: abcdefghijklmnopqrstuvwxyz';
$curl_headers[] = 'X-THING_TWO: 12345678910';

curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_headers);

EDIT: Okay, it looks like you know how CURLOPT_HEADER works. But looking at your code there seems to be a typo right here.

curl_setopt($this->ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_HTTPHEADER, array('API-Token: ' . $this->getToken() ));

Why do you have $this->ch in CURLOPT_HEADER & CURLOPT_HTTPHEADER but just $ch for CURLOPT_RETURNTRANSFER? Shouldn’t that be like this?

curl_setopt($this->ch, CURLOPT_HEADER, true);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_HTTPHEADER, array('API-Token: ' . $this->getToken() ));

EDIT: In addition to that typo, it seems that the original poster needs to know how to get the parameters on the receiving side:

Also how can I read the HTTP headers once the request is made?

Easy. They are accessed via $_SERVER predefined variable in PHP. So you would grab them like this:

$_SERVER['X-API-User-Name'];
$_SERVER['X-API-User-Password'];
$_SERVER['X-API-User-Token'];

And you can check what is passed while debugging by doing this:

echo '<pre>';
print_r($_SERVER);
echo '</pre>';
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for finding the typo. I have corrected that. So it seems that I am doing the setting correctly. How do I ready the the header? how can I get the value of API-Token, API-username, API-password?
the $_SERVER is not returning the username and password. I have updated the question by showing how I trying to access this api from a different server but it is not working. I simply get a blank page. What am I doing wrong? should I update the question with my updated code?
I added the X- as you recommended but I am sitll unable to connect to the API via client.php page

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.