Firestore rest api to make authenticated requests in arduino ide - google-cloud-firestore

i'm making an IOT project with an esp32
the webApi key is hardcoded in a #define.
i have this code working for the auth part
String url = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + String(apiKey);
http.setTimeout(2000);
http.begin(url);
http.addHeader("Content-Type", "application/json");
String dataSent = "{\"email\":\"" + String(email) + "\",\"password\":\"" + String(pswd) + "\",\"returSecureToken\":\"true\"}";
// Issue the HTTP POST request.
int status = http.POST(dataSent);
Serial.println(status);
it returns 200 and the response is parsed, and the idToken is stored in my String token
when i try to make a patch to firestore it returns 401
String url = "https://firestore.googleapis.com/v1/projects/timer-test-soulx/databases/(default)/documents/devices/" + uniqueID + "?key=[" + apiKey + "]"; //working ok
http.setTimeout(1000);
http.begin(url);
http.addHeader("Authorization", "Bearer " + String(token)); //needs fixing
http.addHeader("Accept", "application/json");
http.addHeader("Content-Type", "application/json");
// Issue the HTTP POST request.
int status = http.PATCH(dataSent);
my rules are allow read, write: if request.auth != null;
already tried changing the rules to allow read and write, then commenting out the authorization header and it works perfectly. so i think its clear the problem is the authorization header. am i using a wrong token?

Related

IdentityServer4 implicit grant acr values

I am trying to pass tenant id as parameter to identityserver4 implicit grant end point. The client is written using angularjs, are there any examples to pass the tenantid from angular app to identityserver4 end point.
I have found that this feature was implemented using acr_values. More details are here - https://github.com/IdentityServer/IdentityServer3/issues/348
yes of course. you can always pass userID or any other variable in the state variable of your AUth request. if you include userID as a parameter in your request URL when sending it to Auth server, it'll return the state to redirect URI. which means you'll have access to it there. the issue is when an implicit request is being sent, it practically detaches your app from server cause the response URI (possibly) is in a different state/page. so by passing it as in state, the authorization server includes this value when redirecting the user-agent back to the client.
public Authenticationrequest() {
var client_id = "YOUR-CLIENT-ID";
var scope = "OPTIONAL";
var redirect_uri = "YOUR_REDIRECT_URI";
var response_type = "token";
var authserver = "YOUR-AUTH-SERVER-URL?";
var state = "OPTIONAL"; // put UserID here
var AuthenticationURL = authserver + "response_type=" + response_type + "&scope=" + scope + "&client_id=" + client_id + "&state=" + state + "&redirect_uri=" + redirect_uri;
return AuthenticationURL;
};

Changing user folder collaborating type in box using Salesforce Toolbox

I'm trying to change Box folder collaboration type for user from salesforce Apex trigger. The first thoughts were to use box.Toolkit but it looks like this class does not have updateCollaboration or changeCollaboration method, only create. I guess my only option is to use Box's Rest API. Is there any way I can get service account token in Apex so I can use it in a callout?
I have created a special "Tokens" object in Salesforce with two fields: access token and refresh token. I then have a batch job that runs to update the access token every 55 minutes such that they never expired.
Here is a code snippet in APEX using the Tokens object.
#future(callout=true)
public static void updateTokens(){
//app info for authenticating
String clientID = 'MY_CLIENT_ID';
String clientSecret = 'MY_CLIENT_SECRET';
//look up value of existing refresh token
Token__c myToken = [SELECT Name, Value__c FROM Token__c WHERE Name='Refresh'];
Token__c myAccessToken = [SELECT Name, Value__c FROM Token__c WHERE Name='Access'];
String refreshToken = myToken.Value__c;
String accessToken = myAccessToken.Value__c;
//variables for storing data
String BoxJSON = '';
String debugTxt = '';
//callout to Box API to get new tokens
HttpRequest reqRefresh = new HttpRequest();
reqRefresh.setMethod('POST');
String endpointRefresh = 'https://www.box.com/api/oauth2/token';
reqRefresh.setEndpoint(endpointRefresh);
String requestBody = ('grant_type=refresh_token&refresh_token=' + refreshToken + '&client_id=' + clientID + '&client_secret=' + clientSecret);
reqRefresh.setBody(requestBody);
System.debug('Body of refresh request: ' + requestBody);
//Create Http, send request
Http httpRefresh = new Http();
Boolean successRefresh = false;
while (successRefresh == false){
try{
HTTPResponse resRefresh = httpRefresh.send(reqRefresh);
BoxJSON = resRefresh.getBody();
System.debug('Body of refresh response: ' + BoxJSON);
successRefresh = true;
}
catch (System.Exception e){
System.debug('Error refreshing: ' + string.valueof(e));
if (Test.isRunningTest()){
successRefresh = true;
}
}
}
Keep in mind that if you are using the Box for Salesforce integration your administrator can set the option for the permissions on the folders to sync with Salesforce permissions. This would reverse any changes you make to collaborations. Check out more about Box's Salesforce integration permissions here: https://support.box.com/hc/en-us/articles/202509066-Box-for-Salesforce-Administration#BfS_admin_perm

Yammer API - Posting to External Networks

I've used the Yammer API extensively for accessing current users internal network. All API calls have been working correctly (GET's and POST's) with the original token extracted from;
"https://www.yammer.com/oauth2/access_token.json?client_id={App ID}&client_secret={App Secret}&code={Access Code}"
and using the headers; "Authorization : Bearer {Token}" and "Cookie : {Cookies Received from HTML request}.
I've gotten the tokens for all accessible networks using;
"https://www.yammer.com/api/v1/oauth/tokens.json".
Accessing external networks beyond this point has proved troublesome. I changed the header to "Authorization : Bearer {NetworkToken}". While I am able to GET details from external networks, I cannot POST to external networks. I always receive a '401 Unauthorized' response. The 'Unauthorized' requests include deleting messages and liking messages in external networks.
Is there another step between being able to read data from an external network and enabling POST methods?
If I could get any insight into this i'd be extremely grateful!
Cheers!
When accessing external networks, you need to set the authToken to the authToken for that external network.
Step 1 - Get all auth tokens:
yam.platform.request({
url: "oauth/tokens.json",
type: 'GET',
success: function (msg) {
accessTokens = msg;
/....
},
error: function (msg) {
console.log(msg);
error(msg);
}
Step 2: Set the authToken to the correct external network
var currentToken = "";
$.each(accessTokens, function (i,val) {
if (val.network_permalink == $.cookie('networkPermalink')) {
currentToken = val;
}
});
While I was working on a project last month, I used the following way to post message.
The message has to be Byte encrypted in UTF-8 format.
Specify the content type as "application/x-www-form-urlencoded".
So, an example code would be:
HttpWebRequest a = (HttpWebRequest)WebRequest.Create(postUrl);
a.Headers.Add("Authorization", "Bearer" + authToken);
a.Method = "POST";
byte[] message = Encoding.UTF8.GetBytes("body=" + message + "&replied_to_id=" + threadID);
a.ContentType = "application/x-www-form-urlencoded";
a.ContentLength = message.Length;
using (var postStream = request.GetRequestStream())
{
postStream.Write(message, 0, message.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (var postStreamForResponse = response.GetResponseStream())
{
StreamReader postReader = new StreamReader(postStreamForResponse);
string results = postReader.ReadToEnd();
postReader.Close();
}
I've discovered quite a few inconsistencies quirks with the Yammer API. I've figured out external networks in their totality now. Here are some things that may not be clear;
When doing a POST or DELETE request, do not include the network_permalink in the url! Only include the network_permalink when you're doing a GET request. This was my main issue.
Required request headers;
Content-Type : application/x-www-form-urlencoded
Accept : application/json
Cookie : _workfeed_session_id=(A code that can be extracted from the response from your first request with an auth token)
Authorization : Bearer (Access token for whichever network you wish to access)
Oh and just FYI, to request threads within the 'All Company' group this is the url; https://www.yammer.com/(network_permalink)/api/v1/messages/general.json
Thanks for the answers!

How to run Sharepoint Rest API from server side with elevated privileges?

The Sharepoint Rest API uses a simple URL of the type http://mysite/_api/search/query?querytext='search_key' to return search results as an XML. When I run this directly in a browser, I see a valid XML response:
(1) Am I right in assuming the above response is generated using the current user's authorization?
(2) Can this URL be invoked from server side? I tried it in a web method (WCF web service), but received a 401 - Unauthorized:
public string GetSearchResults(string searchKey)
{
string webURL = SPContext.Current.Web.Url;
string searchURL = webURL + "/_api/search/query?querytext='" + searchKey + "'";
WebClient client = new WebClient();
string xmlResponse = client.DownloadString(searchURL); // throws 401
// parse xmlResponse and return appropriately
}
(3) What I really need is to be able to get the search results irrespective of the current user's access rights (the requirement is that users will see all search results, with an option to "request access" when needed).
I tried this in the above web method, but it still throws the same 401:
public string GetSearchResults(string searchKey)
{
string webURL = SPContext.Current.Web.Url;
string searchURL = webURL + "/_api/search/query?querytext='" + searchKey + "'";
string xmlResponse;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
WebClient client = new WebClient();
xmlResponse = client.DownloadString(searchURL); // still 401
});
// parse xmlResponse and return appropriately
}
What is the right way to invoke the Rest URL from server side? Specifically, from a web method? And how can it be run as super user?
In order to perform REST request, authenticate the request via WebClient.Credentials Property
On Premise (your scenario)
WebClient client = new WebClient();
client.Credentials = new NetworkCredential(userName,password,domain);
SharePoint Online
WebClient client = new WebClient();
client.Credentials = new SharePointOnlineCredentials(username,securedPassword);
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
Search results are always security trimmed by SharePoint so to make this work, you'd need to run your query after specifying new credentials as mentioned by Vadim. This is almost certainly not a good idea. If you're running code server side already, don't use the REST interface, just query directly using the search API.

504 error accessing Kinvey handshake(Rest api)

I have been trying to get the Kinvey handshake for the REST api to work for a while now but have not had any luck. I am using libgdx's net class to send the http request. Wverytime I send the request I get a 504(Gateway Timeout) error. I am following the instructions on the website so I am not sure why I would get that error.
Here is my attempt:
HttpRequest request = new HttpRequest(HttpMethods.GET);
request.setHeader("GET", "/appdata/:App_key");
request.setHeader("Host:", "baas.kinvey.com");
String authHeader = "Basic " + Base64Coder.encodeString("App_key:App_secret");
request.setHeader("Authorization:", authHeader);
request.setUrl("https://baas.kinvey.com/appdata/App_key");
System.out.println("HTTP REQUEST: " + request.getHeaders());
responseListener listener = new responseListener() {
public void handleHttpResponse (HttpResponse httpResponse) {
HttpStatus status = httpResponse.getStatus();
if (status.getStatusCode() >= 200 && status.getStatusCode() < 300) {
System.out.println("HTTP SUCCESS!");
} else {
System.out.println("HTTP ERROR: " + status.getStatusCode());
}
System.out.println("HTTP :" + httpResponse.getResultAsString());
}
#Override
public void failed(Throwable t) {
t.printStackTrace();
System.out.println("REQUEST FAILED!" +t.getMessage());
super.failed(t);
}
};
Gdx.net.sendHttpRequest(request, listener);
As far as I can tell, there is something wrong with the header. I have tested the Url which takes me to a login screen. The login works after I put in the App key as the user name and the Master secret as the password. Is there something obviously wrong? Is there a way I can debug this further?
I'm an engineer at Kinvey and can help you out with this.
A couple things:
first, there are some extra headers there that you don't need. While they might not be the cause of the issue, it is still safe to remove:
request.setHeader("GET", "/appdata/:App_key");
request.setHeader("Host:", "baas.kinvey.com");
Note that GET is set when you create the HttpRequest, and Host is set when you define the URL.
Second, get rid of the colon after "authorization" when setting your header, make it look like this:
request.setHeader("Authorization", authHeader);
Also, you mention that it works with your master secret but not with your app secret? Can you ensure that you are base64 encoding both?
One last thing-- ensure that you replace App_Key with your actual app key, in the URL as well as in the headers.