How to Set and Read a Cookie w/ http-foundation, JWT, & .ENV - php

I have a login processing file in which I am attempting to set a cookie:
$expTime = time() + 3600;
$key = getenv("SECRET_KEY");
$token = array(
"iss" => request()->getBaseUrl(),
"sub" => [$user['id']],
"exp" => $expTime,
"iat" => time(),
"nbf" => time(),
"is_admin" => $user['role_id'] == 1
);
$jwt = JWT::encode($token, $key);
$accessToken = new Cookie('access_token', $jwt, $expTime, '/', getenv("COOKIE_DOMAIN"));
redirect('/', ['cookies' => [$accessToken]]);
I'm using Firebase/JWT to include a JWT as the cookie value. The SECRET_KEY and COOKIE_DOMAIN are pulled in from my .ENV file.
I then call my redirect()
function redirect($path, $extra = []) {
$response = new Response(
null,
Response::HTTP_FOUND,
array('location' => $path)
);
if (key_exists('cookies', $extra)) {
foreach ($extra['cookies'] as $cookie) {
$response->headers->setCookie($cookie);
}
}
$response->send();
}
I then test whether or not the cookie has been set in my index file:
if (request()->cookies->has('access_token')) {
echo "Logged in";
} else echo "No cookie :(";
My problem is that my test is returning "No cookie :(".
Any help would be greatly appreciated.
If you prefer you can fork it on GutHub:
jpradcliffe/user-authentication

I finally resolved the issue with some help (see comments below). The code as it stands above is correct. The issue was in my .env file.

Related

How to verify JWT signature in PHP?

I have a function that generates a JWT :
function getToken($user, $expTime){
$jwt = \Firebase\JWT\JWT::encode([
'iss' => request()->getBaseUrl(),
'sub' => "{$user['id']}",
'exp' => $expTime,
'iat' => time(),
'nbf' => time(),
'is_admin' => $user['role_id'] == 1
], getenv("SECRET_KEY"), 'HS256');
return $jwt;
}
This function returns the below token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJcL2FwaSIsInN1YiI6InVzNWIzY2M4YmRlMDc4MSIsImV4cCI6NTUxMDY1ODkyNDAwMCwiaWF0IjoxNTMwNzM4NTkwLCJuYmYiOjE1MzA3Mzg1OTAsImlzX2FkbWluIjpmYWxzZX0.3bMaxCaMprURZEDurnckZWSoDRp7ePMxZXDW0B6q6fk
When I use this token to make a request I get that:
{
"status": "error",
"message": "Signature verification failed"
}
To make it work I go to https://jwt.io/, add the key and verify it by passing the secret.
Then I get this token :
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIvYXBpIiwic3ViIjoidXM1YjNjYzhiZGUwNzgxIiwiZXhwIjo1NTEwNjU4OTI0MDAwLCJpYXQiOjE1MzA3Mzg1OTAsIm5iZiI6MTUzMDczODU5MCwiaXNfYWRtaW4iOmZhbHNlfQ.heF_L9LrFp7Hht2dbVtOMx_gdUtmPKzrMgxW1_jdWLo
And this works fine. But how to verify it with php code so I can send it to the user?
Code for response:
function loginUser($email, $password) {
try {
// Connecting to databas
$db = new db();
$db = $db->connect();
$user = findUserByEmail($email, $db);
if(empty($user)){
echo 'User not found';
exit;
}
if(!password_verify($password, $user['password'])) {
echo 'Password does not match';
exit;
}
$expTime = time() * 3600;
$jwt = getToken($user, $expTime);
// Close databse
$db = null;
} catch(PDOException $e){
echo $e->getMessage();
}
return $jwt;
}
If you're landing on this page because of a "Signature verification failed" Google search, here is one thing to consider. I was getting this error because there were two spaces between "Bearer" and my token in the Authorization header.
Wrong:
Authorization:Bearer eyJraWQiOiJDT2N...
Correct:
Authorization:Bearer eyJraWQiOiJDT2N...
Ok finally I made it work by changing a little the function that generates the token:
function getToken($user, $expTime){
$key = "secretkey";
$token = array(
'iss' => request()->getBaseUrl(),
'sub' => "{$user['id']}",
'exp' => $expTime,
'iat' => time(),
'nbf' => time(),
'is_admin' => $user['role_id'] == 1
);
return JWT::encode($token, $key);
}

Non supported claims in JWT implementation

I am implementing JWT in my application using php-jwt library from Firebase. I tried the example in the site and it is working fine.
$token = array(
"iss" => "http://example.org",
"aud" => "http://example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
However if I try to include other claims such as exp or sub, it throws UnexpectedValueException ('Wrong number of segments') exception. Has somebody encountered this issue ? Does the php-jwt library supports only the four claims shown in the example ? The code to receive the token in api is given below:
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER["Authorization"]);
}
else if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
//print_r($requestHeaders);
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
$jwt = $matches[1];
}
}
$key = "example_key";
$decoded = JWT::decode($jwt, $key, array('HS256'));
$decoded_array = (array) $decoded;
If the token is generated using the example in the site, then it works fine. If the token is generated using claims like:
$tokenId = base64_encode(mcrypt_create_iv(32));
$issuedAt = time();
$notBefore = $issuedAt + 3;
$expire = $notBefore + 3600;
$token = array(
"iss" => "http://example.com",
"aud" => "http://example.com",
"iat" => $issuedAt,
"nbf" => $notBefore,
"exp" => $expire,
"gate" => "kanchanjuri",
"tokenId" => $tokenId
);
then the api call fails.
From app, the token is sent s follows:
HttpURLConnection con = null;
URL url = new URL(query);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.addRequestProperty("Authorization", "Bearer " + token);
if (con.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ con.getResponseCode());
}
Thanks

How to handle Slim API JWT Authentication

I already generated a token from my api login using this code:
if ($isCorrect == 1) {
$key = "example_key";
$token = array(
"iss" => "http://mywebsite.com",
"iat" => 1356999524,
"nbf" => 1357000000,
'data' => [
'userName' => $UserName,
]
);
$jwt = JWT::encode($token, $key);
$decoded = JWT::decode($jwt, $key, array('HS256'));
$unencodedArray = ['jwt' => $jwt];
echo json_encode($unencodedArray);
}
So I have a token now, how can I use the token to other api? What I mean is, i dont want anybody to perform this api without logging in.
This is my sample API method:
$app->get('/api/user/{UserId}', function($request){
//Select query here
});
This is the library i used: https://github.com/firebase/php-jwt
Thank you very much for your help.
You Just need to add a middleware method for your API
that will check the validation of the JWT token with that user name
Then pass the request to the API
`
$app->add( function ( $Req ,$Res ,$next ){
//get token,username from the user
$token= $Req->getParsedBodyParam('token');
$user_name=$Req->getParsedBodyParam('username');
//check for empty of any of them
if(empty ($token)|| empty($user_name) ){
$message=array("success"=>false,'message'=>'Some data is empty');
return $Res->withStatus(401)
-> withJson($message);
}
else{
//Validation test for the taken for this user name
$decoded_token = $this->JWT::decode($token, 'YourSecret key', array('HS256'));
if( isset($decoded_token->data->userName) && $decoded_token->data->userName == $user_Name ){
$message=array('message'=>'the token is valid');
//pass through the next API
$Res=$next($Req,$Res->withJson($message));
return $Res;
}
else{
$message=array("sccess"=>false,"message"=>"Token Validation Error",'code'=>201);
return $Res->withStatus(401)
->withJson($message);
}
}
});
`

Linkedin 401 [unauthorized] Invalid or expired token error

I have a requirement to authenticate my site with Linkedin. Am using following code to get linkedin Access token. I can see from the linkedin docs the validity of token is 60 days. Everything works for me am getting access token, i can see the "expires_in" as 5183999 seconds id (60 days).
My problem is when i request for userinfo using this token after 2 days, am getting a error 401 response. The access token lifetime is not stable. I have searched a lot for 401 error, read so may links but not get the exact answer. Why am getting this 401 error ?
Please help me to solve this issue. Your help is much appreciated.
{
errorCode: 0,
message: '[unauthorized] Invalid or expired token.',
requestId: 'P7IR3JY3GZ',
status: 401,
timestamp: 1410937984755
}
// PHP CODE TO GET ACCESS TOKEN
<?php
// Change these
require "config.php";
//define('API_KEY', $ );
//define('API_SECRET', 'secret' );
//define('REDIRECT_URI', 'redirecturl');//http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME']);
define('SCOPE', 'w_messages rw_company_admin r_fullprofile r_emailaddress rw_nus r_network rw_company_admin rw_groups' );
// You'll probably use a database
session_name('linkedin');
session_start();
// OAuth 2 Control Flow
if (isset($_GET['error'])) {
// LinkedIn returned an error
print $_GET['error'] . ': ' . $_GET['error_description'];
exit;
} elseif (isset($_GET['code'])) {
// User authorized your application
if ($_SESSION['state'] == $_GET['state']) {
print_r("ssssssssssssssssssssssssssssssssssssssss");
// Get token so you can make API calls
getAccessToken();
} else {
// CSRF attack? Or did you mix up your states?
exit;
}
} else {
if ((empty($_SESSION['expires_at'])) || (time() > $_SESSION['expires_at'])) {
// Token has expired, clear the state
$_SESSION = array();
}
if (empty($_SESSION['access_token'])) {
// Start authorization process
print_r("ddddddddddddddddddddd");
getAuthorizationCode();
}
}
// Congratulations! You have a valid token. Now fetch your profile
$user = fetch('GET', '/v1/people/~:(id,first-name,last-name,picture-url)');
$pages = fetch2('GET', '/v1/companies:(id,name,logo-url)');
$user->pages = $pages;
$user->accesstoken = $_SESSION['access_token'];
echo "expiry time". $_SESSION['expires_in'];
print_r($pages);
print_r($user);
$SCRIPT = '<script>window.opener.postMessage('.json_encode($user) .',"*");</script>';
session_name('linkedin') ;
session_unset();
echo $SCRIPT;
echo '<h1>', HtmlSpecialChars($user->firstName),
' you have logged in successfully with LinkedIn!</h1>';
echo '<pre>', HtmlSpecialChars(print_r($user, 1)), '</pre>';
//print "Hello $user->firstName $user->lastName.";
exit;
function getAuthorizationCode() {
$params = array('response_type' => 'code',
'client_id' => API_KEY,
'scope' => SCOPE,
'state' => uniqid('', true), // unique long string
'redirect_uri' => REDIRECT_URI,
);
// Authentication request
$url = 'https://www.linkedin.com/uas/oauth2/authorization?' . http_build_query($params);
// Needed to identify request when it returns to us
$_SESSION['state'] = $params['state'];
// Redirect user to authenticate
header("Location: $url");
exit;
}
function getAccessToken() {
$params = array('grant_type' => 'authorization_code',
'client_id' => API_KEY,
'client_secret' => API_SECRET,
'code' => $_GET['code'],
'redirect_uri' => REDIRECT_URI,
);
// Access Token request
$url = 'https://www.linkedin.com/uas/oauth2/accessToken?' . http_build_query($params);
// Tell streams to make a POST request
$context = stream_context_create(
array('http' =>
array('method' => 'POST',
)
)
);
// Retrieve access token information
$response = file_get_contents($url, false, $context);
// Native PHP object, please
$token = json_decode($response);
// Store access token and expiration time
$_SESSION['access_token'] = $token->access_token; // guard this!
$_SESSION['expires_in'] = $token->expires_in; // relative time (in seconds)
$_SESSION['expires_at'] = time() + $_SESSION['expires_in']; // absolute time
return true;
}
function fetch($method, $resource, $body = '') {
$params = array('oauth2_access_token' => $_SESSION['access_token'],
'format' => 'json',
);
// Need to use HTTPS
$url = 'https://api.linkedin.com' . $resource . '?' . http_build_query($params);
// Tell streams to make a (GET, POST, PUT, or DELETE) request
$context = stream_context_create(
array('http' =>
array('method' => $method,
)
)
);
// Hocus Pocus
$response = file_get_contents($url, false, $context);
// Native PHP object, please
return json_decode($response);
}
function fetch2($method, $resource, $body = '') {
$params = array('is-company-admin'=>'true','format' => 'json','oauth2_access_token' => $_SESSION['access_token'],
);
// Need to use HTTPS
$url = 'https://api.linkedin.com' . $resource . '?' . http_build_query($params);
// Tell streams to make a (GET, POST, PUT, or DELETE) request
$context = stream_context_create(
array('http' =>
array('method' => $method,
)
)
);
// Hocus Pocus
$response = file_get_contents($url, false, $context);
// Native PHP object, please
return json_decode($response);
}

LinkedIn API to get 1st degree connections and company name, positions and industry?

I am using this code to access the LinkedIn API and it's working perfectly, but it only gets details like first name, last-name, headline, and email.
I want to get the user's connections, company name, company type, company size, positions, and industry.
How can I get these details through the LinkedIn API ?
<?php
// Change these
define('API_KEY', [api_key]);
define('API_SECRET', [api_secret]);
define('REDIRECT_URI', 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME']);
define('SCOPE', 'r_fullprofile r_emailaddress rw_nus r_network');
// You'll probably use a database
session_name('linkedin');
session_start();
// OAuth 2 Control Flow
if (isset($_GET['error'])) {
// LinkedIn returned an error
print $_GET['error'] . ': ' . $_GET['error_description'];
exit;
} elseif (isset($_GET['code'])) {
// User authorized your application
if ($_SESSION['state'] == $_GET['state']) {
// Get token so you can make API calls
getAccessToken();
} else {
// CSRF attack? Or did you mix up your states?
exit;
}
} else {
if ((empty($_SESSION['expires_at'])) || (time() > $_SESSION['expires_at'])) {
// Token has expired, clear the state
$_SESSION = array();
}
if (empty($_SESSION['access_token'])) {
// Start authorization process
getAuthorizationCode();
}
}
$user = fetch('GET', 'http://api.linkedin.com/v1/people/id=12345/connections');
print_r($user);
$name = $user->firstName.' '.$user->lastName;
$email = $user->emailAddress;
$occupation = $user->headline;
exit;
function getAuthorizationCode() {
$params = array('response_type' => 'code',
'client_id' => API_KEY,
'scope' => SCOPE,
'state' => uniqid('', true), // unique long string
'redirect_uri' => REDIRECT_URI,
);
// Authentication request
$url = 'https://www.linkedin.com/uas/oauth2/authorization?' . http_build_query($params);
// Needed to identify request when it returns to us
$_SESSION['state'] = $params['state'];
// Redirect user to authenticate
header("Location: $url");
exit;
}
function getAccessToken() {
$params = array('grant_type' => 'authorization_code',
'client_id' => API_KEY,
'client_secret' => API_SECRET,
'code' => $_GET['code'],
'redirect_uri' => REDIRECT_URI,
);
// Access Token request
$url = 'https://www.linkedin.com/uas/oauth2/accessToken?' . http_build_query($params);
// Tell streams to make a POST request
$context = stream_context_create(
array('http' =>
array('method' => 'POST',
)
)
);
// Retrieve access token information
$response = file_get_contents($url, false, $context);
// Native PHP object, please
$token = json_decode($response);
// Store access token and expiration time
$_SESSION['access_token'] = $token->access_token; // guard this!
$_SESSION['expires_in'] = $token->expires_in; // relative time (in seconds)
$_SESSION['expires_at'] = time() + $_SESSION['expires_in']; // absolute time
return true;
}
function fetch($method, $resource, $body = '') {
$params = array('oauth2_access_token' => $_SESSION['access_token'],
'format' => 'json',
);
// Need to use HTTPS
//$url = 'https://api.linkedin.com' . $resource . '?' . http_build_query($params);
$url = $resource . '?' . http_build_query($params);
// Tell streams to make a (GET, POST, PUT, or DELETE) request
$context = stream_context_create(
array('http' =>
array('method' => $method,
)
)
);
// Hocus Pocus
$response = file_get_contents($url, false, $context);
// Native PHP object, please
return json_decode($response);
}
?>
For 1st degree connections, you may only retrieve basic profile fields and you can use like this. for reference http://developer.linkedin.com/documents/connections-api
$user = fetch('GET', 'http://api.linkedin.com/v1/people/~/connections:
(id,first-name,last-name,location:(name),picture-url)');

Categories