I am creating a API in Codeigniter.
In this API I have a login function for user. If Login is successful I set user data in CI session and return the session back to user.
Now is it possible that user can use that session id to validate himself for all his other requests like add/update/delete. Basically I want that when the user sends next request I can validate his credentials based on his session id.
Client Request Code :
public function login()
{
$url = 'http://localhost/bizCloudDS/server/login';
$timestamp = gmdate("His");
$parameters = array("reqest"=>"login", "username"=> "admin", "API_AccessKey"=> "b5741564rda4a4d91965d3b5", "GMT_Timestamp"=> $timestamp);
$json = json_encode($parameters);
$encrypted = $this->bizEncrypt($json , 'enc' );
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS, $encrypted);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
echo $result;
curl_close($ch);
}
Now above was a sample request from client to server for Login.
On Server Side the server validates the credentials give by the client, if validated returns this json response :
{"ResponseCode":"200","Reason":"Success","Session_ID":"euo1obqeekd5vtb0ult9nj84kii1kqni"}
Now I want that if the user send another request lets say create_user in this he will send the session_id returned from the login request. So how can i fetch the session data by this session id on server side?
Is this good practice ?
you are on wrong way:
I recomand:
Use database and cookie for login (not sessions). OR
You need persistant curl connection (explore CURLOPT_COOKIEJAR) to understand how you login then use same session for other things.
If the user isn't logged directly into your system, but is using a third-party tool via API, then using the session ID doesn't make sense because there actually is no session in the traditional sense. It's a one time call/response.
It seems a better idea to use some sort of request signature to verify that the individual accessing your system is who they say they are and have the access to do what they're trying to do (ie some kind of key hash). For each call, you would authenticate the call itself, not an active session.
Or you can use a persistent cURL connection, but that could be more prone to headache.
Related
I am using a cross domain and uses php server to get user info when logging in. In my running website I use php code and when the user login I added this code
session_start();
Then just declare the user info when successfully logged in like:
$_SESSION['user_id'] = $user['user_id'];
$_SESSION['user_email'] = $user['user_email'];
$_SESSION['user_name'] = $user['user_name'];
And then I use that session $user['user_id']; in every user requests.
How to implement a session when the user logged on Hybrid app? Is it the same on how my running website works? Do I just need to add session code on the ajax request? Any idea?
To do this you need a host server that will authenticate and talk to your devices. Common protocols would be the use of cURL and JSON response:
REMOTE DEVICE
1) Your device, I will use another server because it's easy, will start a connection using cURL:
function cURL($variables = false)
{
$url = "http://www.example.com/";
$query = (!empty($variables))? '?'.http_build_query($variables) : '';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url.$query);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if(!empty($response))
$data = json_decode($response,true);
curl_close($ch);
return $data;
}
$login = cURL(array(
'service'=>'login',
'apikey'=>123123,
'username'=>'whatever',
'password'=>'whatever')
);
print_r($login);
API HOST SERVER
2) Your server then will be listening for services. I am using $_GET but $_POST is better:
if(!empty($_GET['service'])) {
switch($_GET['service']) {
case('login'):
logInUser($_GET);
}
}
The logInUser() function would just do the normal login function except that it would set timestamp, token, apikey, and username in the database and return that via json on success:
//...authentication code here...//
if($valid) {
// However you want to make a token
$token = md5($usename.mt_rand(1000000,9999999).time());
// Do code here to save the username, token, apikey, timestamp into database
// This will then echo back the token on success to the device
die(json_encode(array('token'=>$token,'success'=>true)));
}
else {
die(json_encode(array('token'=>'','success'=>'bad username/password')));
}
After this point, the device calls back to the host with the token in the query string as well as the apikey. It would also include a service and any variables that the service requires to send data back to the device. Every hit to the server triggers the server to look for an apikey, then service, then if service is not login, would require the token. It would query the database and check that all those things in the database are valid. If the token exists and the timestamp is recent enough (you can set the expiration time on that) then service runs. After service runs (or before complete), the timestamp value for the token is updated to current time.
I am trying to securely login a user via their Google account.
I am at the stage that I retrieve the userID and oAuthToken using this cordova plugin.
Now I am at the point where I need to send these credentials to my server and then on the server side validate the integrity of the token. Essentially I am trying to perform this part of the process.
I am confused as to which token I should try to verify using the Google client api. Should I use the userID or the oAuthToken ?
The documentation mentions validating the userID but I find this strange. Wouldn't this mean that if anyone gets my user id they can essentially break into my server ? The user id never changes (correct me if I am wrong here) so it seems insecure to validate on this. Wouldn't it make more sense to validate the oAuthToken which is set to expire ? Or does the user ID also expire ?
Any advice would be welcome.
Thanks,
Fido
Edit:
For anyone interested. My confusion arose due to not understanding fully three tokens which the google api can return: userId, oAuthToken, and idToken.
Briefly:The userId is returned with most api calls identifying the user. This appears to be constant. The oAuthToken in my case was returned when I accessed the google api as an Android client. The tokenId is returned when accessing the api as a web client. So those wishing to do server side validation using a mobile retrieved token should access the api as a web client. The token returned can then be validated server side using code similar to the accepted answer below.
you need to validate the IdToken, never send the userId on an open line. the IdToken expires quickly and it is virtually impregnable to brute force impersonation attacks.
this php snippet receives an HTTP request that starts with idtoken=, validates your token serverside and returns either the complete array or user email:
<?php
$inputRaw = file_get_contents('php://input');
$idToken= substr($inputRaw,8);
$fp = fopen('twoStepOutput.txt', 'a');
$url = 'https://www.googleapis.com/oauth2/v3/tokeninfo?id_token='.$idToken;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$json = json_decode($response, true);
curl_close($ch);
$userEmail = $json["email"];
$clientId = $json["azp"];
//fwrite($fp, date("YmdHis")."\r\n$idToken\r\n");
fwrite($fp, date("YmdHis")."\r\n");
fwrite($fp, "email Confirmed by GOOGLE:[$userEmail]\r\n");
//print_r($json); // returns array console readable
print_r($clientId); // returns google client id for verification (without transfering user data)
fclose($fp);
?>
just in case you are in doubts, this is what an IdToken looks like:
eypZCI6OiJSUzI1JhbGciNiIsImtIjk4MzQxMzgyMWJmMzhiNTJlM4OTI2YTllMTc0YTc5MWMwNGMifQ.eyJpc3MiOi3VizExYJhY2NvdW50cy5nb29nbGUuY29tIiwicmEIjoiMTAzNDUyNjAwODM5NzY3MjU2MDE0IiwiYXpwIjoiMTA3OTMxMTEyNTc1OS1lYWJhbWV0b2ZldjIwY28zbGQ5b2o1YWQwMzFuZG9nMC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImVtYWlsIjoidG9ueWdpbGJyQGdtYWlsLmNvbSIsImF0X2hhc2giOiJaSkhxbUZHcnR5Y29kdEhhOGJvMEYWY1NTk2NzUsImV4cCVBIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjEwNzkzMTExMjU3NTkt1ldG9mZXYyMGNvM2xkOW9qNWFkMDMxbmRvZzAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJpYXQiOjE0MzZWFiI6MTQzNjU2MzI3NSwibmFtZSI6IlRvbnkgR2lsIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tQVREckRSbF9UdFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBRncvOVdDQnZkYlpUTEEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IlRvbnkiLCJmYW1pbHlfbmFtZSI6IkdpbCIsImxvY2FsZSI6ImVuIn0.L4peW11TD0bDOlvYKNY60ieZ1sbZfW9gEImcuxVA5f9U_4N49Io1CFXoGKmEPR_ij4q38tF2drPMOKijQePwlrxDui37ubzAdVkuksCJUobzjD1_eccF_8GldP5Y1_XsU8xrZeEnfabfiYpr-VwoLzIeNNUdy9SUbUWjMHNcvf4dGFMzE_SONHr57igjHK3rGkbvLo-UduFngm3e-EL0YR2zOKOVj1Qs8g8_qpWgkn8XABTme1thmuU8OfC-HaF9_B2Zk2UCsnOu4ApiYZk3DPIKgeX6AF11kYnzgvciYheWeddly0foT4G00C7w_wgtd-LSRw0XZltec_MPMa2QSA
Am writing an api for IOS application
I have some concerns about handling session for the IOS application
When a user login from iphone, I need to pass the session id as login response and use that session id
in further api calls for validating the user,
What I have done in my api controller is get the session id and save it to session array along with user details and pass the session id as response
$session = $this->session->userdata('session_id');
$user_array = array(
'email' => $user->email,
'session_id'=>$session
);
$this->session->set_userdata('logged_in', $user_array);
$output = array(
'code'=>200,
'user'=>$user,
'session_id'=>$session
);
$this->output
->set_content_type('application/json')
->set_output(json_encode($output));
For the further api calls, I will get the session_id as a parameter,
I checked its a valid section or not using the following. code
$session_id = $this->input->get('session_id', TRUE);
if($session_id){
if($this->session->userdata('logged_in')){
$user = $this->session->userdata('logged_in');
if($user['session_id'] == $session_id){
// valid session
}
This worked well when tested with postman.
But am not sure , this is the correct way to handle session with API calls.
Will the same work when run from the IOS application?
thanks in advance
You are using a REST api method which is stateless, So session will not get maintained while calling from IOS application. Every call you make from the app will have a new session.
You have to use SOAP as a web service if you really need session to be maintained while API call.
For more information please check on If REST applications are supposed to be stateless, how do you manage sessions?
I have a PHP script that needs to fetch a CSV file from an application. There is an API for the application that allows the script to lot in, which gives the script a session cookie for authentication. I then need to doa GET request to fetch the CSV file (which the API does not support).
Using curl directory works:
$c = curl_init($url);
curl_setopt($c, CURLOPT_COOKIE, 'PHPSESSID=' . $session_id_from_api);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$csv_file = curl_exec($c);
echo $csv_file;
That fetches the CSV file using the session ID obtained from the API login and passed through a coookie.
Now, I would like to do the same thing using Guzzle, but I just get the login page back instead. This is the code I'm using:
$client = new Guzzle\Http\Client();
$request = $client->get(
$url,
[
'cookies' => ['PHPSESSID' => $session_id_from_api],
]
);
$response = $client->send($request);
echo $response->getBody(true);
That gives me the login page, so the GET to the application is not recognising the session defined by the cookie.
Is there anything else I need to do to ensure the cookie and value I specify is sent to the remote application?
Edit: looking at $request->getRawHeaders(), I see this line in the headers:
cookies: vec6nb1egvvui6op7qr7b0oqf6
That obviously isn't right. The documentation for my version of Guzzle gives this example:
// Enable cookies and send specific cookies
$client->get('/get', ['cookies' => ['foo' => 'bar']]);
which looks to me to be consistent with what I am passing to Guzzle.
Just to be clear, I am not trying to manage cookies in both directions over multiple requests, so there is no need to store any cookies. I have a cookie name and its value (from another source), and I just want to make sure that name and value gets sent to the destination for a single GET request. I'm not trying to "maintain a session", but in a way I am having a session passed to me from another part of the application (not Guzzle) and need to set my Guzzle request up to use it.
Well, this seems to work. Guzzle was not sending the cookie without being sure the domain it was sending it to was correct:
// Set up a cookie - name, value AND domain.
$cookie = new Guzzle\Plugin\Cookie\Cookie();
$cookie->setName('PHPSESSID');
$cookie->setValue($session_id_from_api);
$cookie->setDomain($domain_of_my_service_url);
// Set up a cookie jar and add the cookie to it.
$jar = new Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar();
$jar->add($cookie);
// Set up the cookie plugin, giving it the cookie jar.
$plugin = new Guzzle\Plugin\Cookie\CookiePlugin($jar);
// Register the plugin with the client.
$client->addSubscriber($plugin);
// Now do the request as normal.
$request = $client->get($url);
$response = $client->send($request);
// The returned page body.
echo $response->getBody(true);
I'm using cURL to login on a website but the problem is, all login actions are registered on the server and it is impossible to login each time I want to perform a certain action.
I tried to do it this way:
$curl = curl_init();
some curl_setopts();
$_SESSION["curl"] = $curl;
so I could use it if needed on another moduels of my site (for different purposes but each of them require me to be logged in). It does not work. curl_exec won't work with $_SESSION["curl"] ("supplied argument is not a valid cURL handle resource").
How to handle that?
For every action I need to be logged but I don't want to login with cURL to perform different action separately.
Any help would be appreciated.
Its impossible to store variable $curl to $_SESSION because curl_init return type resource. From docs Session - Introduction.
Because session data is serialized, resource variables cannot be stored in the session.