Validating token when client returns to server - php

I am developing an API using PHP and got the authentication part, I'm using token authentication.
This is the logical sequence I want to implement.
User Requests Access with Username / Password
Application validates credentials
Application provides a signed token to the client
Client stores that token and sends it along with every request
Server verifies token and responds with data
Example of use
user informs email and password, {"email":"emiry#hotmail.com", "senha":"123"}
I then send a token eiy#omlo3
whenever it accesses the API then it passes me that token
how will I know if this token is valid or not? will I have a function to validate the valid token? What is the logic to do this? to know if the token is valid

You could use the JWT (JSON Web Token) standard to learn more about this process. JSON web tokens are broken up into three parts all separated by a period:
header.payload.signature
The header is created by making claims about the token, for example its type and algorithm used:
$header = json_encode(['type' => 'JWT', 'algorithm' => 'HS256']);
More information on the difference between the signing algorithms
The payload contains important information that is used by the application, for example an identifier for a user. It can also contain other information like the expiration, issuer, etc:
$payload = json_encode([
'user_id' => 56,
// set expiration to 2 hours from now etc
]);
These can then by encoded with the base64_encode() and hash_hmac() functions.
The signature is a special part. It is a concatenation of the header and payload, with an appended "secret". The secret is a string that is only known by you and your application. Adding this to your token "signs" it, and makes it so that you're the only one that can properly validate it. This might be a good site to generate a "secret".
You would store the secret in a secure place outside of your publicly accessible folder, and retrieve it when needed (dotenv libraries are great for this). Those are all appended together and encoded to create your token and give to the client.
When you receive the token to validate, you can explode it into three parts since each is separated by a period, and then validate each piece to your liking. For example if you received a token you could do the following:
// validate token in header.payload.signature format
$token = explode('.', $token);
$header = $token[0]; // header should be first
$payload = $token[1]; // payload should be second
$signature = $token[2]; // signature should be third
Remember the signature is a hash of the header, payload, and secret. So you could decode this, and compare it to $token[0] and $token[1] to ensure that the token was not tampered with, and finally make sure that the secret matches as well.
Reference: How to Create a JSON Web Token Using PHP

Related

How to validate a token without a database?

I have hosted two domains on the same server, domain A and domain B.
Domain A will generate the unique access token to the content of domain B.
Domain A
<?php
//http://php.net/manual/en/function.phpversion.php
//echo 'Version of PHP: ' . phpversion();
session_start();
//$expiry_timestamp = time() + $expiry;
//https://davidwalsh.name/random_bytes //https://secure.php.net/random_bytes
//$token = bin2hex(random_bytes(64));
$token = bin2hex(openssl_random_pseudo_bytes(64));
//$time_token = 12000;
//$time_token = srand(floor(time() / $time_token));
//echo $token;
$_SESSION['token']=$token;
?>
<html>
<head>
</head>
<body>
Content 1
</body>
</html>
The process of generating a token seems to be the right one, it has been easy to generate it.
Now comes my problem, how can I validate the generated token from domain A to domain B ?. The generated token must only be valid for the content that generated the token, the token must not be valid for other content, the token must be unique so that user can not share access to another user if it is not from his or her computer, the token must be valid only for 4 hrs of access after 4 hrs the token will no longer be valid to display the content must generate a new token to access again.
Can this process be done using a cookie without using a database?
Maybe identifying both domains A and B using a key, something like that
$APP_SECRET_KEY = "key code secret";
Using a shared secret key is a good approach here.
I tend to use HMAC when I need to generate and validate a token (e.g.: E-Mail verification) and don't want to store it in a DB. Plus, HMAC is built in to PHP, so no library is needed here.
The idea is, on top of your data, you add a signature to verify that this token was created by your application on Domain A. You generate the token the same way again on Domain B to verify it.
Example:
Shared function to generate the token:
function buildVerificationToken($expires, $content)
{
// Same function on both domains
$APP_SECRET_KEY = 'key code secret'; // Maybe move that out of source code
$tokenData = [
'expires' => $expires, // Include it in signatur generation to prevent user from changing it in URL
'content' => $content, // Create different token for different content
'ip' => $_SERVER['REMOTE_ADDR'], // Identify the browser to make it not shareable. Best approach I could think of for this part.
];
$serialized = json_encode($tokenData);
return hash_hmac('sha256', $serialized, $APP_SECRET_KEY);
}
Generate the token on Domain A:
<?php
$expires = time() + (4 * 3600); // +4h
?>
Content 1
Verify it on domain B:
$providedExpires = (int) $_GET['expires'];
$providedToken = $_GET['token'];
$verificationToken = buildVerificationToken($providedExpires, 'content1'); // Build token the same way
if (!hash_equals($verificationToken, $providedToken)) { // hash_equals instead of string comparison to prevent timing attacks
// User provided forged token, token for another content, or another IP
die('Bad token'); // However you want to handle this
}
if (time() > $providedExpires) { // Check expiry time. We can trust the user did not modify it as we checked the HMAC hash
die('Token expired'); // However you want to handle this
}
// User is allowed to see content1
Json Web Token (JWT) seems to fit your requirements. Both applications use one secret key to exchange tokens with encrypted data one another.
Example use-case:
Let the secret key $secret="secret"
The raw data tells us the Unix timestamp when the token is generated (the iat field), the user id (the sub field) and the content id (the content field)
$data = [
"sub" => "1234567890",
"iat" => 1516239022,
"content" => 1
];
Application A encodes the raw data with the secret key using HS256 algorithm ($token = jwt_encode($raw, 'HS256', $secret)). The output $token will be:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJjb250ZW50IjoxfQ.idM7d2fgmJVk3WjANwG-Gt6sY0lyE3eTvpKRpwITHRs
You can parse the token to see its content in the JWT home page.
The token is send to the application B. This application decodes the token with the same algorithm and shared secret key ($raw = jwt_decode($token, 'HS256', $secret)). The raw data will be available in the application B. This data can be used to validate the token:
Read the user id from sub field and check if it is correct
Read the content id from content field and check if it is correct
Read the timestamp when the token is generated from the iat field and check if it is in the last 4 hours.
There are several PHP libraries implement JWT for you.

PHP authentication with JWT

I'm creating a sort of 'social network'. Now I'm creating the authentication part. Today I learned about JSON Web Tokens.
1) I read that JWT's are safe to use, because the are signed with a secret key. But then I found some tools online like https://jwt.io. I tried to build some JWT tokens with PHP using firebase/php-jwt. The tools like jwt.io can extract the data I put in the JWT (like user ID). How can this be safe? Can't someone just create a new JWT using the old one but with a different user ID?
An example: I created the following token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJNeUFQIiwiaWF0IjoxNTE2NTYzMTM0LCJleHAiOjE1MTY1NjQzNDAsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6ImFkbWluQGV4YW1wbGUuY29tIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOiJmYWxzZSJ9.dCtYVpFXhoQmzOdX_dW1yFHEcZ9aZ1I9MC33lJGapvY
If you paste this token in jwt.io, you'll see the payload is "name: John Doe" and "admin: false". Isn't this unsafe? Or is it safe because you NEED the secret key to recreate a JWT.
Off the record: You cannot store senstive information in a JWT I guess...
2) How to "login" a user using PHP and JWT's? I created a quick demo, I'm not sure the code "works" but I guess you'll see what I mean.
if (isset($_POST['submit'])) {
$user = $_POST['user'];
$pass = $_POST['pass'];
if($user = 'my_username' && $password == 'my_password') {
// user is logged in
// create a JWT here
} else {
// wrong credentials!
}
}
Now, the question/problem is: how to store this token? In a cookie? In a session? Using HTML5's localStorage? What is the safest way to do this?
And secondly: how to authenticate the user? I would do it like this:
// my secret key
$secret = 'MY_SECRET_KEY';
// decode the token
$token = JWT::decode($token, $secret, array('HS256'));
// what to do here?
Can you match this token with some data in a database or something?
1) The JWT token is not encrypted, so the data inside it can be easily read. However, it contains a signature that can be validated only with the secret key you have set when creating the token. You can check the signature to see that the token has not been tampered with.
2) The token can be stored anywhere, since it's so small. Just remember that the token can be easily read, but not altered. Don't store any sensitive data in the tokens.
When checking the token, the important things to check are the signature and the exp time to see that the token is still valid. A well-constructed token doesn't need full database validation, but rather just check that the user's privileges haven't been changed since issuing the token, and if they have, recreate the token with the updated data or force the user to log in again.

Make Oauth API calls with existing Access Token and Access Token Secret

I am using the Lusitanian PHP Oauth library (https://github.com/Lusitanian/PHPoAuthLib).
After the user gets authorized in my application, i have received values of Access Token and Access Token Secret. Now with these values, i would like to make authenticated calls to API. How can i make the calls with the values of Access Token, Access Token Secret, along with the values of Consumer Key and Consumer Secret? I don't want to get the user authorized every time, to make API calls for him. Does anyone have an idea ?
My request goes like this:
$result = json_decode( $service->request( '/users/getDetails' ), true
);
I have tried the REST Client of Firefox and Advanced REST Client of Chrome, that perform OAuth calls successfully, with just the values of Access Token, Access Token Secret, Consumer Key and Consumer Secret.
Similarly, i would like to perform the OAuth calls from my PHP code. The library which i am using, depends on Session to store these values (which requires the user to login each time) and build the Authorization header and signature. Is there a way i can build the Signature and Authorization header from my end manually and make the OAuth calls ?
Finally, i have tweaked the functionality of reusing the access tokens.
I am fetching token from a config php file, after i store the token in it.
The token can also be stored in a local PHP session and read from it.
The code for storing token is in Service/AbstractService.php:
$this->storage->storeAccessToken($this->service(), $token);
You can modify it like the following, to store the token in a session variable:
if(!isset($_SESSION['access_token'])) {
$token = new StdOAuth1Token();
$token->setRequestToken($access_token);
$token->setRequestTokenSecret($access_token_secret);
$token->setAccessToken($access_token);
$token->setAccessTokenSecret($access_token_secret);
$token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
$_SESSION['access_token'] = serialize($token);
}
Then when making a request to API, you can modify the code in request() function to use token from your session:
Change:
$token = $this->storage->retrieveAccessToken($this->service());
To:
$token = unserialize($_SESSION['access_token']);
This way, i could use custom PHP sessions to store and retrieve access tokens. You can also use Database or a text file to store and retrieve the tokens. It works! Hope it would be useful for someone.

How to implement 'Token Based Authentication' securely for accessing the website's resources(i.e. functions and data) that is developed in PHPFox?

I want to use methods and resources from the code of a website which is developed in PHPFox.
Basically, I'll receive request from iPhone/Android, I'll get the request and pass to the respective function from the PHPFox code, take the response from that function and return it back to the device.
For this purpose I've developed REST APIs using Slim framework.
But the major blocker I'm facing currently is in accessing the resources(i.e. functions and data) of PHPFox website.
I'm not understanding how should I authenticate the user using 'Token Based Authentication' in order to access the website's resources.
If someone could guide me in proper direction with some useful working example it would be really helpful for me.
N.B. : The proposed implementation of 'Token Based Authentication' should be very secure and fast in speed. The security should not be compromised in any way.
Following is the code I tried on my own but I don't know whether it's right or wrong. Is my approach correct or wrong. Please someone analyse it and let me know your feedback on it.
To create a token i use this function which takes as parameters, the user's data
define('SECRET_KEY', "fakesecretkey");
function createToken($data)
{
/* Create a part of token using secretKey and other stuff */
$tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"]; // It can be 'stronger' of course
/* Encoding token */
$token = hash('sha256', $tokenGeneric.$data);
return array('token' => $token, 'userData' => $data);
}
So a user can authentified himself and receive an array which contains a token (genericPart + his data, encoded), and hisData not encoded :
function auth($login, $password)
{
// we check user. For instance, it's ok, and we get his ID and his role.
$userID = 1;
$userRole = "admin";
// Concatenating data with TIME
$data = time()."_".$userID."-".$userRole;
$token = createToken($data);
echo json_encode($token);
}
Then the user can send me his token + his un-encoded data in order to check :
define('VALIDITY_TIME', 3600);
function checkToken($receivedToken, $receivedData)
{
/* Recreate the generic part of token using secretKey and other stuff */
$tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"];
// We create a token which should match
$token = hash('sha256', $tokenGeneric.$receivedData);
// We check if token is ok !
if ($receivedToken != $token)
{
echo 'wrong Token !';
return false;
}
list($tokenDate, $userData) = explode("_", $receivedData);
// here we compare tokenDate with current time using VALIDITY_TIME to check if the token is expired
// if token expired we return false
// otherwise it's ok and we return a new token
return createToken(time()."#".$userData);
}
$check = checkToken($_GET['token'], $_GET['data']);
if ($check !== false)
echo json_encode(array("secureData" => "Oo")); // And we add the new token for the next request
Am I right?
Thanks.
1st you should understand what's token based authentication. It could be explained as below.
The general concept behind a token-based authentication system is
simple. Allow users to enter their username and password in order to
obtain a token which allows them to fetch a specific resource -
without using their username and password. Once their token has been
obtained, the user can offer the token - which offers access to a
specific resource for a time period - to the remote site.
Read more
Now let's see what are the steps of implementing it in your REST web service.
It will use the following flow of control:
The user provides a username and password in the login form and clicks Log In.
After a request is made, validate the user on the backend by querying in the database. If the request is valid, create a token by
using the user information fetched from the database, and then return
that information in the response header so that we can store the token
browser in local storage.
Provide token information in every request header for accessing restricted endpoints in the application.
If the token fetched from the request header information is valid, let the user access the specified end point, and respond with JSON or
XML.
See the image below for the flow of control
You might be wondering what's a JWT
JWT stands for JSON Web Token and is a token format used in
authorization headers. This token helps you to design communication
between two systems in a secure way. Let's rephrase JWT as the "bearer
token" for the purposes of this tutorial. A bearer token consists of
three parts: header, payload, and signature.
The header is the part of the token that keeps the token type and encryption method, encoded in base64.
The payload includes the information. You can put any kind of data like user info, product info and so on, all of which is also stored in
base64 encoding.
The signature consists of combinations of the header, payload, and secret key. The secret key must be kept securely on the server-side.
You can see the JWT schema and an example token below;
You do not need to implement the bearer token generator as you can use php-jwt.
Hope the above explains your confusion. if you come across any issues implementing token based authentication let me know. I can help you.

How is basic authentication header validated/checked in a rest api

I'm building a very tiny api.
In the api im authenticating the request using basic authentication header coming from the request.
This is the code upto which I have done
$headers = apache_request_headers() ;
// print_r($headers);
if(isset($headers['Authorization'])){
//$credentials = base64_decode($headers);
print_r($headers['Authorization']);
}
I got the Authorization header as 'Basic YXBpa2V5OmFqZWVzaA==' Now how will I check if this basic authorization header is valid?
Should I decode the base64 string in the username:password format and check it with the DB or when the username and pass is generated,do I have to store it in a base64 format and compare the request base64 string with the one in DB??
I would like to know what is the standard practice of validating a basic authentication request?
Please suggest some ideas. I am just starting up, please excuse stupidity in questions.
i suggest you to use a api token rather than a user/password combination. with a simple auth token you get two benefits.
Usernames or Passwords may change with the time and if so the user is forced to change all usernames and passwords in his application to get there application back to work. a simple token are constant and don't require any change when the username and password of the user changed.
With basic auth the client need to send there username + password in a unencrypted format. this is not very secure and on the worst case, unauthorized can login into the service backend with username + password from the request. simple token are only valid for api calls.
Generate a simple random token for each API user like Eq57dwypZaFW4f2xxRzFaGjwCYinOn6l13Mvds00P2ZzgdMPTk and require to send this token on each api request with the request header like
X-API-TOKEN: Eq57dwypZaFW4f2xxRzFaGjwCYinOn6l13Mvds00P2ZzgdMPTk
X-API-CLIENT-ID: 123456
on the server side validate with
<?php
$token = $_SERVER['X-API-TOKEN'];
$userID = $_SERVER['X-API-CLIENT-ID'];
$isValid = $findInDatabase->findToken($userID, $token);
if( $isValid )
{
// process api request
} else {
// invalid token
}

Categories