This question already has answers here:
Google GCM server returns Unauthorized Error 401
(14 answers)
Closed 6 years ago.
CURL --header "Authorization: key=XXXXXXXXX" --header "Content-Type: application/json" https://android.googleapis.com/gcm/send -d "{\"registration_ids\":[\"XXXXXXXX\"]}"
this is my request,
im trying to send this from my cmd,
with the api key i created in google console with my endpoint as registration_ids.
but this is what i get :
<HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
any ideas ?
thx :)
Navigate to the https://console.developers.google.com/apis/credentials?project=<project-name>
then pick the server key you created. At the bottom of the page you could add whitelisted IP's/ranges.
You're getting 401 Unauthorized because GCM is only accepting requests from HTTPS-based hosts, which your local console is not.
The easiest way to verify this (if you don't already have HTTPS-based website) is:
STAGE 1 - getting HTTPS-enabled website
Create account on CloudFlare
Change your domain's DNS to CloudFlare's
Enter your server's IP in CloudFlare console
Enable free HTTPS (and disable cache - it may be tricky sometimes)
Now traffic to your website will be redirected through CloudFlare.
Traffic from your clients to CloudFlare will be encrypted, and traffic from CloudFlare to your server won't.
While it's not 100% secure, it allows to secure most common vector of attack - malicious internet provider etc and it takes very little effort to get free service worker-ready website.
If you want your own cert, you can use Let's Encrypt
STAGE 2 - putting GCM sender on your HTTPS server
I have example code for you in PHP:
<?
function sendPushNotification($data, $ids)
{
echo("<br><br><b>Sending notifications...</b>");
// Insert real GCM API key from the Google APIs Console
$apiKey = 'AIza...';
// Set POST request body
$post = array(
'registration_ids' => $ids,
'data' => $data,
);
// Set CURL request headers
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
// Initialize curl handle
$ch = curl_init();
// Set URL to GCM push endpoint
curl_setopt($ch, CURLOPT_URL, 'https://gcm-http.googleapis.com/gcm/send');
// Set request method to POST
curl_setopt($ch, CURLOPT_POST, true);
// Set custom request headers
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Get the response back as string instead of printing it
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Set JSON post data
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post));
// Actually send the request
$result = curl_exec($ch);
// Handle errors
if (curl_errno($ch))
{
echo 'GCM error: ' . curl_error($ch);
}
// Close curl handle
curl_close($ch);
// Debug GCM response
echo $result;
}
$data = array('message' => 'JAAAREEEEK!');
// Please note that currently push payload is not supported. However if you're reading this answer from the future it might work
// The recipient registration tokens for this notification
// https://developer.android.com/google/gcm/
$ids = ['registrationid1','registrationid2']
// Send push notification via Google Cloud Messaging
sendPushNotification($data, $ids);
I had exactly the same problem and this solution solved it. If you'll have any further problems, please give me a shout.
Related
I'm new to the Playable Locations API and am trying to make my first request. Based on the documentation I'm using the endpoint https://playablelocations.googleapis.com/v3:samplePlayableLocations&key=MY_API_KEY however it returns a 404 error
Is there another URL I should be using for these requests?
EDIT: This seems to be related to the way I'm passing the API key. If I remove &key=MY_API_KEY I no longer get the 404 error. Instead it's a 403 with message The request is missing a valid API key. Am I using the wrong parameter to pass the key?
Below is the code I'm using:
$api_key = 'MY_API_KEY';
$request_url = "https://playablelocations.googleapis.com/v3:samplePlayableLocations&key=$api_key";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request_url);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_exec($ch);
curl_close($ch);
Please do note that though it is already available in the public documentations, currently Playable locations API is not publicly launched yet. That might be one of the reasons why you are not able to use it currently. Also, in your Playable locations request, make sure that you are using your own valid API key under your Google Maps project as well as enable the Playable Locations API in your GCP console for you to be able to use this in your implementation.
If you have not generated a valid API key and enabled Playable Locations API in your GCP console yet, here are guides you can check:
Create an API key: https://www.youtube.com/watch?v=2_HZObVbe-g
Enable an API: https://www.youtube.com/watch?v=n1UorU1PALk
Also, it seems you have added the "key" parameter in your request incorrectly. Instead of doing https://playablelocations.googleapis.com/v3:samplePlayableLocations&key=
It should be https://playablelocations.googleapis.com/v3:samplePlayableLocations?key=
It seems that there is an error in the documentation that's worth filing for a documentation bug in the Google Maps' Public Issue Tracker.
In addition, you need to have the request body for your Playable Locations API which looks like this:
{
"areaFilter": {
"s2CellId": string,
},
"criteria": [
{
"gameObjectType": number,
"filter": {
"maxLocationCount": number,
"spacing": {
"minSpacingMeters": number,
"pointType": enum(PointType)
},
"includedTypes": [
string
],
},
"fieldsToReturn": string
}
]
}
More information here: https://developers.google.com/maps/documentation/gaming/using_playable_locations
I have been hacking away at this for a few days with no luck.
I am trying to make a secure (SSL/HTTPS) API request in an Arduino environment. The controller I am using is an ESP32, which connects through wifi fine, and can retrieve/post data. However I am having no luck connecting to a secure API.
I'm trying to connect to this API https://strike.acinq.co/documentation/api-reference
EXAMPLE CURL REQUEST IN API'S DOCUMENTATION:
$ curl https://api.dev.strike.acinq.co/api/v1/charges \
-u sk_pJDwxFxCVw5fQJhRRMpf29jReUjjN: \
-X POST \
-d amount=42000 \
-d currency="btc" \
-d description="1%20Blockaccino"
Here is my Arduino code, I am using the ArduinoJson.h and WiFi.h libraries:
// Connect to HTTP server
WiFiClient client;
client.setTimeout(10000);
if (!client.connect("api.strike.acinq.co", 80)) {
Serial.println(F("Connection failed"));
return;
}
Serial.println(F("Connected!"));
// Send HTTP request
client.println(F("GET /api/v1/charges?id=MYKEY&amount=4200¤cy=btc HTTP/1.0"));
client.println(F("Host: api.strike.acinq.co"));
client.println(F("Content-Type: application/x-www-form-urlencoded"));
client.println(F("Connection: close"));
if (client.println() == 0) {
Serial.println(F("Failed to send request"));
return;
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return;
}
A 401 "Invalid API Key" Is the closest I have got. I know the API-key works, and that I am just using it wrong. I've tried moving the key to:
client.println(F("id: MYKEY"));
but that didn't work either.
I have tried other libraries and ArduinoJson seems to be the best. I think the issue is the fact its a secure server and the layout of my request. I found many resources for connecting to open API's on Arduino, but nothing on connecting to secure ones. I think I am almost there with the code...
UPDATE
So I have updated my code. I am still trying to use ArduinoJson. I can connect to the API but it keeps spitting out "HTTP/1.1 400 BAD_REQUEST". I don't know weather this is because its over HTTPS or the formatting of my request.
In the API docs -u and -X don't have a field name like "amount=4200", so I am assuming -u would just be added client.print("?="+apiKey);
//open weather map api key
String apiKey= "myapikey";
int status = WL_IDLE_STATUS;
char server[] = "api.strike.acinq.co";
Serial.println("\nStarting connection to server...");
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
Serial.println("connected to server");
// Make a HTTP request:
client.print("POST /api/v1/charges");
client.print("?="+apiKey);
client.print("&amount=4200");
client.print("¤cy='btc'");
client.println("&description='sweets'");
client.println("Host: api.strike.acinq.co");
client.println("Connection: close");
client.println();
}
else {
Serial.println("unable to connect");
}
UPDATE
I figured out the println and print actually mean something and have subsequently organised my request much better. It still comes back with 400 Unauthorized?
String PostData = "&description=\"car\"&amount=1000¤cy=\"sweetsandthat\"";
client.println("POST /api/v1/charges HTTP/1.1");
client.println("Host: api.strike.acinq.co");
client.println("Authorization: Basic "+apiKey);
client.print("Content-Length: ");
client.println(PostData.length());
client.println(); // blank line required
client.println(PostData);
Serial.println("POSTED DATA: " + PostData);
// client.stop();
client.println();
} else {
Serial.println("unable to connect");
}
delay(1000);
String line = "";
while (client.connected()) {
line = client.readStringUntil('999');
Serial.println(line);
Serial.println("parsingValues");
//create a json buffer where to store the json data
StaticJsonBuffer<5000> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(line);
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
//get the data from the json tree
String nextWeatherTime0 = root["id"][0];
// Print values.
Serial.println(nextWeatherTime0);
}
client.println("Connection: close");
client.stop();
}
Check the response for a BAD request, We usually get it when we deal with a bad URL or URL not found. check whether you are connecting to the same url mentioned in docs.
First connect to the api and after that make queries like providing your api key and feilds
remove this.
client.println("Host: api.strike.acinq.co");
and use GET request to get the response of the data you have in these fields
String PostData = "&description=\"car\"&amount=1000¤cy=\"sweetsandthat\""
I have also been struggling to get an https post to work on the esp32. A few things, the wifi.h module, I believe, does not support https. The WiFiClientSecure.h does, and you need to set the port to 443. I have also failed to get a POST to work, but I succeed in a basic GET test connection to howsmysssl.com. Andreas Spiess covers this well in a youtube video. He goes beyond SSL to establishing trust. I just want basic SSL to work, so if you get this figured out, please let me know. Hopefully I got you one step closer. :)
I'm trying to add a place using the google places API.
The API IS enabled and the API key is valid. Here is my code:
$url = "https://maps.googleapis.com/maps/api/place/add/json?key=MYKEY";
$content = json_encode('{
"location": {
"lat": 55.9868532,
"lng": -4.5780577
},
"accuracy": 50,
"name": "Home Made Pizza",
"types": ["other"],
"website": "http://example.com",
"language": "en-AU"
}');
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER,
array("Content-type: application/json"));
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 201 ) {
die("response $json_response");
};
curl_close($curl);
$response = json_decode($json_response);
The response I am getting is
response { "status" : "REQUEST_DENIED" }
Help :-)
Based from this thread, make sure that you have enabled your API in the Console.
You are using http(s) for calling Google API, is your html also hosted under http(s). If not try changing google url to http.
Otherwise every thing else kinda looks ok so that makes me think you might wanna check your api console again, go to SERVICES and check if your 'Places API' is turned ON.
You can also try changing the Port address to 443 to get response from Places API
Here are some links which might also help:
Google Places API - REQUEST_DENIED
PHP: Google Places API return REQUEST_DENIED
The problem here was that I was using "json_encode" on json.
I did not need to encode it and this was throwing an error.
Morale of the story, don't Json_encode Json.
I am looking to generate the BOX access token using Refresh Token.
I want to do it periodically before the refresh Token expires.
How can i automate it without logging to the web application.
From the website, i can generate the token. but i am looking at to automate the job to create the token perdiodically to avoid the token expiration.
Any Ideas?
Create a database in which you store the access token, the refresh token, and the generated date of the access token.
When you work in your application, check by the date in the database if your access token is expired. If expired, create a function to generate an access token having a refresh token. Here's the V2 way of generating that access token using cUrl:
curl https://www.box.com/api/oauth2/token \
-d 'grant_type=refresh_token&refresh_token={valid refresh token}&client_id={your_client_id}&client_secret={your_client_secret}' \
-X POST
which will return a json answer like this:
{
"access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl",
"expires_in": 3600,
"restricted_to": [],
"token_type": "bearer",
"refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR"
}
Here's the link of the original tutorial:
http://developers.box.com/oauth/
Here's an example of getting a new access/refresh token using cUrl and PHP:
function getAccessTokenByRefresh($refreshToken, $client_id, $client_secret){
$defaultOptions = array(
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_VERBOSE => true,
CURLOPT_HEADER => false,
CURLINFO_HEADER_OUT => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => false,
);
$ch = curl_init('https://www.box.com/api/oauth2/token');
$options = $defaultOptions;
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = array(
'grant_type'=>'refresh_token',
'refresh_token'=>$refreshToken,
'client_id'=>$client_id,
'client_secret'=>$client_secret
);
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
After you generated the new access token, save them in the database, and save the time when you generated the access for further comparisons.
You’ll authenticate once to get an access_token but after that a crontab will take care of refreshing the token every 15 minutes. The PHP code is at:
http://liljosh.com/upload-to-box-content-api-without-user-authentication/
I am trying to use the Google Drive API via their PHP Client Library to upload a large file. Currently it fails because the only method seemingly available is the "simple" upload method. Unfortunately that requires you to load the entire file as data and it hits my php memory limit. I would like to know if it is possible and see an example of how it is done. I know there is a method for resumable and chuncked uploads, but there is no documentation on how to use it.
<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
$client = new Google_Client();
// Get your credentials from the APIs Console
$client->setClientId('YOUR_CLIENT_ID');
$client->setClientSecret('YOUR_CLIENT_SECRET');
$client->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
$service = new Google_DriveService($client);
$authUrl = $client->createAuthUrl();
//Request authorization
print "Please visit:\n$authUrl\n\n";
print "Please enter the auth code:\n";
$authCode = trim(fgets(STDIN));
// Exchange authorization code for access token
$accessToken = $client->authenticate($authCode);
$client->setAccessToken($accessToken);
//Insert a file
$file = new Google_DriveFile();
$file->setTitle('My document');
$file->setDescription('A test document');
$file->setMimeType('text/plain');
$data = file_get_contents('document.txt');
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => 'text/plain',
));
print_r($createdFile);
?>
Looks like this has been answered already? Read the file as a stream, one chunk at a time and add that to a buffer/write it straight to the socket:
Google Drive API - PHP Client Library - setting uploadType to resumable upload