I'm using laravel 5.3 with the GoCardless API and I'm trying to build out the endpoints so my application can handle events accordingly.
I'm reading the GoCardless documentation and it says do the following:
$token = getenv("GC_WEBHOOK_SECRET");
$raw_payload = file_get_contents('php://input');
$headers = getallheaders();
$provided_signature = $headers["Webhook-Signature"];
$calculated_signature = hash_hmac("sha256", $raw_payload, $token);
if ($provided_signature == $calculated_signature) {
} else {
};
I've converted the above into Laravel friendly controller speak.
public function hook(Request $request)
{
$token = env("GC_WEBHOOK_SECRET");
$raw_payload = $request;
$provided_signature = $request->header('Webhook-Signature');
$calculated_signature = hash_hmac("sha256", $raw_payload, $token);
if ($provided_signature == $calculated_signature) {
Log::info('It was a match!');
} else {
Log::info('Something went wrong!');
};
}
but I can't get the $provided_signature to match the $calculated_signature, I've got a feeling it's something to do with the way I'm hashing the token from my env file.
Solved it guys, all I needed to do was replace
$raw_payload = $request;
with
$raw_payload = $request->getContent();
Related
I have tried using old v4.9 endpoints that haven't been replaced by v1 so far such as:
https://developers.google.com/my-business/reference/rest/v4/accounts.locations/reportInsights
https://developers.google.com/my-business/reference/rest/v4/accounts.locations.reviews
However, none of these endpoints work anymore.
I am using PHP client that had these endpoints missing, but using the official v4.9 library listed here: https://developers.google.com/my-business/samples/previousVersions I have been able to reach some of the old endpoints such as reviews.
However they no longer return any data or data object is empty.
Anyone has experienced similar issues?
The v4.9 (not yet deprecated) endpoints such as reviews, insights etc. are working, but the official library is broken and botched.
I had to code a replacement using Guzzle client reaching to the endpoints directly instead. So you need to code the API library yourself from scratch for these v4.9 endpoints as the official library does not work.
How to fetch reviews:
public static function listReviews($client, $params, $account, $location)
{
$response = $client->authorize()->get('https://mybusiness.googleapis.com/v4/' . $account . '/' . $location . '/reviews', ['query' => $params]);
return json_decode((string) $response->getBody(), false);
}
How to fetch insights:
/** v4.9 working 02/2022 **/
public static function reportInsights($client, $params, $account)
{
try {
$response = $client->authorize()->post('https://mybusiness.googleapis.com/v4/' . $account . '/locations:reportInsights', [
\GuzzleHttp\RequestOptions::JSON => $params,
]);
} catch (\GuzzleHttp\Exception\RequestException $ex) {
return $ex->getResponse()->getBody()->getContents();
}
return json_decode((string) $response->getBody(), false);
}
How to prepare payload for insights:
$params = new \stdClass();
$params->locationNames = $account->name . '/' . $location->name;
$time_range = new \stdClass();
$time_range->startTime = Carbon::parse('3 days ago 00:00:00')->toISOString();
$time_range->endTime = Carbon::parse('2 days ago 00:00:00')->toISOString();
if ($force == 'complete') {
$time_range->startTime = Carbon::parse('17 months ago 00:00:00')->toIso8601ZuluString();
$time_range->endTime = Carbon::parse('3 days ago 00:00:00')->toIso8601ZuluString();
}
$params->basicRequest = new \stdClass();
$params->basicRequest->timeRange = $time_range;
$params->basicRequest->metricRequests = new \stdClass();
$metric_request = new \stdClass();
$metric_request->metric = 'ALL';
$metric_request->options = ['AGGREGATED_DAILY'];
$params->basicRequest->metricRequests = [
$metric_request,
];
Note: if you are getting empty insights response, you have to check verification using new v1 API call such as:
$verifications = \Google_Service_MyBusinessVerifications($client)->locations_verifications->listLocationsVerifications($location->getName());
$verification = '0';
if ($verifications->getVerifications()) {
$verification = $verifications->getVerifications()[0]->getState();
}
Using official API client with an existing token (needs to be fetched via OAuth2):
$provider = new GoogleClientServiceProvider(true);
$client = $provider->initializeClient($known_token, ['https://www.googleapis.com/auth/plus.business.manage', 'https://www.googleapis.com/auth/drive']);
I have the next code, got directly from google reference (https://developers.google.com/identity/sign-in/web/backend-auth)
public function verifyFromAndroid($idToken=null) {
if(empty($idToken)) {
$idToken = self::SAMPLE_ID_TOKEN;
}
$client = new Google_Client(['client_id' => self::CLIENT_ID]);
$payload = $client->verifyIdToken($idToken);
if ($payload) {
print_r($payload);
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
var_dump($payload);
$this->lastError = "Invalid ID token";
return false;
}
}
But this method always returns false, even using a valid id token that is created and working using the oauthplayground online tool.
The next code works fine, using directly the GoogleAccessToken_Verify class. Can someone tell me why the official Google code doesn't work and yes my own code using the official Google-clien-php sdk?
try {
$verify = new Google_AccessToken_Verify();
$result = $verify->verifyIdToken($this->idToken);
if($result) {
print_r($result);
$friendlyData = $this->translateData($result, true);
if(!$friendlyData) {
return false;
}
return $friendlyData;
}
else {
$this->lastError = "Invalid token verification, no error code";
return false;
}
}
catch(UnexpectedValueException $ex) {
$this->lastError = "UnVaEx (Code {$ex->getCode()}): {$ex->getMessage()}";
return false;
}
try adding complete client ID
xxxxxxxxxxxxxx-xxxxx-yy-zz.apps.googleusercontent.com
while initiating the
$client = new Google_Client(['client_id' => self::CLIENT_ID]);
It should work i was also facing the same issue ...
Had a similar issue.Deleted my android app on firebase console and created a fresh app wirh debug key sha1.Then downloaded and replaced my google.json into my app.This fixed my issue.This has happened to me twice now. At times you just need to recreate the android app on firebase console.
Before you begin register your backend URL at https://developers.google.com/identity/sign-in/web/sign-in with Configure your project button and don't use any credidentials or api key in your code. After doing them your code should look like to this.
public function verifyFromAndroid($idToken=null) {
if(empty($idToken)) {
$idToken = self::SAMPLE_ID_TOKEN;
}
//As you notice we don't use any key as a parameters in Google_Client() API function
$client = new Google_Client();
$payload = $client->verifyIdToken($idToken);
if ($payload) {
print_r($payload);
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
var_dump($payload);
$this->lastError = "Invalid ID token";
return false;
}
}
I hope it helps.
I faced the same issue. After checking different PHP versions, I found that the google client library is working in PHP7.4 but not with PHP8.0.
Please try the below code after downgrading the version of PHP to 7.4
require_once 'vendor/autoload.php';
$id_token = $_POST['credential'];
$client = new Google_Client(['client_id' => $CLIENT_ID]); // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
// Invalid ID token
}
Or For development and debugging, you can call google oauth2 tokeninfo validation endpoint.
https://oauth2.googleapis.com/tokeninfo?id_token=$id_token
I have an API built with Slim v2 and I secure certain routes passing a middleware function "authenticate":
/**
* List marca novos
* method GET
* url /novos/marca/:idmarca
*/
$app->get('/novos/marca/:idmarca', 'authenticate', function($idmarca) {
$response = array();
$db = new DbHandler('dbnovos');
// fetching marca
$marca = $db->getMarcaNovos($idmarca);
$response["error"] = false;
$response["marca"] = array();
array_walk_recursive($marca, function(&$val) {
$val = utf8_encode((string)$val);
});
array_push($response["marca"], $marca);
echoRespnse(200, $response, "marcaoutput");
})->via('GET', 'POST');
The authenticate function checks if a headers Authorization value was sent (user_api_key) and checks it against the database.
I'm trying to get the same functionality in a Slim v3 API with the folowwing route:
/**
* List marca novos
* method GET
* url /novos/marca/:idmarca
*/
$app->get('/novos/marca/{idmarca}', function ($request, $response, $args) {
$output = array();
$db = new DbHandler('mysql-localhost');
$marca = $db->getMarcaNovos($args['idmarca']);
if ($marca != NULL) {
$i = 0;
foreach($marca as $m) {
$output[$i]["id"] = $m['id'];
$output[$i]["nome"] = utf8_encode($m['nome']);
$i++;
}
} else {
// unknown error occurred
$output['error'] = true;
$output['message'] = "An error occurred. Please try again";
}
// Render marca view
echoRespnse(200, $response, $output, "marca");
})->add($auth);
This is my middleware
/**
* Adding Middle Layer to authenticate every request
* Checking if the request has valid api key in the 'Authorization' header
*/
$auth = function ($request, $response, $next) {
$headers = $request->getHeaders();
$outcome = array();
// Verifying Authorization Header
if (isset($headers['Authorization'])) {
$db = new DbHandler('mysql-localhost');
// get the api key
$api_key = $headers['Authorization'];
// validating api key
if (!$db->isValidApiKey($api_key)) {
// api key is not present in users table
$outcome["error"] = true;
$outcome["message"] = "Access Denied. Invalid Api key";
echoRespnse(401, $outcome, $output);
} else {
global $user_id;
// get user primary key id
$user_id = $db->getUserId($api_key);
$response = $next($request, $response);
return $response;
}
} else {
// api key is missing in header
$outcome["error"] = true;
$outcome["message"] = "Api key is missing";
//echoRespnse(400, $response, $outcome);
return $response->withStatus(401)->write("Not allowed here - ".$outcome["message"]);
}
};
But I always get the error: "Not allowed here - Api key is missing"
Basically, the test if $headers['Authorization'] is set is failing. What is the $headers array structure or how do I get the Authorization value passed through the header?
If you are sending something else than valid HTTP Basic Authorization header, PHP will not have access to it. You can work around this by adding the following rewrite rule to your .htaccess file.
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
I'm using Laravel/Lumen as an API for the backend of a webapp and run into a hiccup.
In an example I have a route that does not need the user to be authenticated. But I do want to check in the routes controller if the user visiting has a valid token.
So I wrote the following:
if ($tokenFetch = JWTAuth::parseToken()->authenticate()) {
$token = str_replace("Bearer ", "", $request->header('Authorization'));
} else {
$token = '';
}
I believe the above will check the Bearer token is valid else it will return a blank variable.
The following is my entire Controller.
public function show($url, Request $request)
{
if ($tokenFetch = JWTAuth::parseToken()->authenticate()) {
$token = str_replace("Bearer ", "", $request->header('Authorization'));
} else {
$token = 'book';
}
return response()->json(['token' => $token]);
}
The Problem
If I a pass in a valid Token Bearer, it returns the token but if I pass in an invalid one I get the following error:
TokenInvalidException in NamshiAdapter.php line 62:
Token Signature could not be verified.
If I don't pass a token at all:
JWTException in JWTAuth.php line 195:
The token could not be parsed from the request
Is there a way to check if a token is passed and if it has then check if its valid, but also if one has not been passed then return a blank return?
You can wrap it inside try/catch block
public function show($url, Request $request)
{
try {
$tokenFetch = JWTAuth::parseToken()->authenticate())
$token = str_replace("Bearer ", "", $request->header('Authorization'));
}catch(\Tymon\JWTAuth\Exceptions\JWTException $e){//general JWT exception
$token = 'book';
}
return response()->json(['token' => $token]);
}
There are few exceptions that you might want to handle separately (jwt-auth/Exceptions)
Also as you're using laravel 5 you can global handling for JWT exceptions ,not recommended in this case but you should know of this option and choose yourself. app/Exceptions/Handler.php and inside render method add [at the top]
if ($e instanceof \Tymon\JWTAuth\Exceptions\JWTException) {
//what happen when JWT exception occurs
}
Yes it's possible to achieve what you want.
Check if a token is passed:
If you check in the documentation of parseToken you'll see that the algorithm to check if we pass a token is:
if (! $token = $this->parseAuthHeader($header, $method)) {
if (! $token = $this->request->query($query, false)) {
}
}
// which it will be in your case:
$hasToken = true;
$header = $request->headers->get('authorization');
if (! starts_with(strtolower('authorization'), 'bearer')) {
if (! $request->query('token', false)) {
$hasToken = false;
}
}
Check if a token is valid:
Please note that the NamshiAdapter use the Namshi\JOSE package so read the documentation here.
In NamshiAdapter.php as you can see the line who rise your error are:
if (! $jws->verify($this->secret, $this->algo)) {
throw new TokenInvalidException('Token Signature could not be verified.');
}
// in your case:
// + try to var_dump $this->secret, $this->algo
// + use Namshi\JOSE\JWS
// if you var_dump
$jsw = new JWS(['typ' => 'JWT', 'alg' => $algo]);
$jws = $this->jws->load($token, false);
// if you want to follow the documentation of Namshi\JOSE
$jws = JWS::load($tokenString, false, $encoder, 'SecLib');
// again var_dump for $this->secret, $this->algo
$isValidToken = ($jws->verify($this->secret, $this->algo));
I am working on php soap to implement an insurance policy issuing application.Everything i set and i get a response number from web service.But i dont know how to fetch the response data from web service (xml).Below i am providing my web service request and response.
Link to web service
https://es.adpolice.gov.ae/TrafficInsurance/TrafficInsuranceServicesNew.asmx?op=CreateVehicleInsurancePolicy
this is the code i am trying..please guide me.
class SOAPStruct
{
function __construct($user, $pass)
{
$this->userName = $user;
$this->Password = $pass;
}
}
$service = new SoapClient("https://es.adpolice.gov.ae/TrafficInsurance/TrafficInsuranceServicesNew.asmx?wsdl", array('trace' => 1));
$auth = new SOAPStruct('*****','****');
$header = new SoapHeader("http://adpolice.gov.ae/TrafficInsurance/TrafficInsuranceServices.asmx",'SoapHeaderIn',$auth,false);
$service->__setSoapHeaders(array($header));
$param = array('lngInsuranceCompanyCode'=> '1','intInsuranceKindCode'=>'1','lngTcf'=>'1','strPolicyNo'=>'1','dtExpiryDate'=>'2016-04-30','dtStartDate'=>'2015-03-31','strChassisNo'=>'6T1BE4DFDFDFDFD','strRemarks'=>'dfdf','strUserCreated'=>'dfdfd');
$response = $service->CreateVehicleInsurancePolicy($param);
print_r($response);
All you have to do is
$xml = $service->__getLastResponse();
print_r($xml);