This question probably doesn't belong to one single developer group, but the Esri-Leaflet implementation is the ultimate end goal, and probably has developers most familiar with the stack - so here goes:
I have a standalone ArcGIS server situation, and am wanting to access secure feature services. My site runs on PHP 7.3, and has access to cURL. Ideally I'd like to collect the token using credentials stored in PHP, using cURL, and then deliver that token to Esri-Leaflet when I do an addtomap, thus keeping the credentials secure.
The error that I'm facing at the response to the request is the rather generic:
{"error":{"code":498,"message":"Invalid Token","details":[]}}
Temporarily there is a url here:
http://52.65.144.150/esri-js-demo-page/
So, what have I done so far? Lets use a secured esri demo service to illustrate, noting that I've left in commented out sections where I've either:
<?php
//Check to see if the request came from the proper application
//The url to the token endpoint of the sever containing the secure service
$url = "https://sampleserver6.arcgisonline.com/arcgis/tokens/";
//What is the actual referer - dump it into the page for debugging purposes
echo $referer = $_SERVER['HTTP_REFERER'];
//The fields included in the request
$fields = array(
'request' => 'getToken',
'username' => 'user1',
'password' => 'user1',
'expiration' => 120,
'clientid' => 'ref.' . $_SERVER['HTTP_REFERER'],
//'clientid' => 'ref.' . $_SERVER['HTTP_REFERER'],
//'clientid' => 'ip.' . $_SERVER['HTTP_CLIENT_IP'],
//'clientid' => 'ip',
//'ip' => $_SERVER['REMOTE_ADDR'],
'f' => 'json'
);
$fields_string = "";
foreach($fields as $key=>$value) {
$fields_string .= $key.'='.$value.'&';
}
//Instantiate Curl
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//curl_setopt($ch, CURLOPT_REFERER, $referer);
$result = curl_exec($ch);
//If Curl was not instantiated successfully
if (!curl_exec($ch)) {
echo 'An error has occurred: ' . curl_error($ch);
}
//Otherwise return the result
else {
preg_match('/:.*?,/', $result, $token);
$token = str_replace(':', "", $token);
$token = str_replace('.",', '"', $token);
//print_r($token);
echo '<script type="text/javascript">';
echo 'var val = '.$token[0];
echo '</script>';
//echo $result;
}
//Close Curl
curl_close($ch);
}
}
Now, reload the page that is doing the calling, see that the token is brought in via javascript successfully:
<script type="text/javascript">var val = "9VOz2HXe_mfOXJSVSFr4cgNL-5k6fIMfqTOYytKEefs"</script>
Request the service layer:
var pedestrianDistricts2 = L.esri.featureLayer({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire_secure_ac/FeatureServer/2',
token: val
}).addTo(map);
The request from the network tab of Chrome looks like:
https://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire_secure/FeatureServer/?token=9VOz2HXe_mfOXJSVSFr4cgNL-5k6fIMfqTOYytKEefs&f=json
The response looks like:
{"error":{"code":498,"message":"Invalid Token","details":[]}}
As an aside I tried this morning to hard code the credentials into a html page as per one of the examples - I was able to get around this error. Since this will be a production system I cannot take this approach. Then I had a different issue altogether, but that's another matter.
I cannot help but think that the referer is causing me grief, but I'm just not sure how to get around the issue.
Any bright ideas are appreciated!
Solved! Go to Solution.
Fixed by treating the json object as json properly.
<?php
//Establish our requesting url
global $wp;
$RequestingPage = home_url( $wp->request );
//Check to see if the request came from the proper application
//The url to the token endpoint of the server containing the secure service
$url = "https://someplace.com/arcgis/tokens/";
//The fields included in the request
$fields = array(
'request' => 'getToken',
'username' => 'username1',
'password' => 'password1',
'expiration' => 120,
'clientid' => 'ref.' . $RequestingPage . '/',
'f' => 'json'
);
$fields_string = "";
foreach($fields as $key=>$value) {
$fields_string .= $key.'='.$value.'&';
}
//Instantiate Curl
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_REFERER, $RequestingPage);
$result = curl_exec($ch);
//If Curl was not instantiated successfully
if (!curl_exec($ch)) {
echo 'An error has occurred: ' . curl_error($ch);
}
//Otherwise return the result
else {
//Treat the response as JSON, and split by attribute.
$someObject = json_decode($result);
echo '<script type="text/javascript">';
echo "\r\n";
echo 'var val = "'.$someObject->token .'"';
echo "\r\n";
echo '</script>';
echo "\r\n";
}
//Close Curl
curl_close($ch);
}
}
add_action( 'wp_head', 'ple_hook_javascript' );
Fixed by treating the json object as json properly.
<?php
//Establish our requesting url
global $wp;
$RequestingPage = home_url( $wp->request );
//Check to see if the request came from the proper application
//The url to the token endpoint of the server containing the secure service
$url = "https://someplace.com/arcgis/tokens/";
//The fields included in the request
$fields = array(
'request' => 'getToken',
'username' => 'username1',
'password' => 'password1',
'expiration' => 120,
'clientid' => 'ref.' . $RequestingPage . '/',
'f' => 'json'
);
$fields_string = "";
foreach($fields as $key=>$value) {
$fields_string .= $key.'='.$value.'&';
}
//Instantiate Curl
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_REFERER, $RequestingPage);
$result = curl_exec($ch);
//If Curl was not instantiated successfully
if (!curl_exec($ch)) {
echo 'An error has occurred: ' . curl_error($ch);
}
//Otherwise return the result
else {
//Treat the response as JSON, and split by attribute.
$someObject = json_decode($result);
echo '<script type="text/javascript">';
echo "\r\n";
echo 'var val = "'.$someObject->token .'"';
echo "\r\n";
echo '</script>';
echo "\r\n";
}
//Close Curl
curl_close($ch);
}
}
add_action( 'wp_head', 'ple_hook_javascript' );
This works out for me. Thanks Simon
Glad it helped!
I guess what I didn't mention in my initial series of posts was that the script returns the variable "var" which contains the token.
When collecting a layer with ESRI-Leaflet you can supply this token as part of the URL. Just for anyone else who happens upon this in the future.