Can't hit Google plus api after oauth with Firebase - oauth

2 hours trying to get this to work and I can't. Firebase authenticates the user just fine, but then it can't fetch anything from the Google Plus API.
The error you will get:
{
domain: "global"
location: "Authorization"
locationType: "header"
message: "Invalid Credentials"
reason: "authError"
}
The code is this:
Auth.$authWithOAuthPopup(provider, {
scope: ['profile', 'email']
}).then(function(authData) {
console.log(authData.token);
gapi.client.setApiKey('<APIKEY>');
gapi.client.load('plus','v1', function(){
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function(resp) {
console.log('Retrieved profile for:' + resp.displayName);
debugger;
});
});
}, showError);
It must have something to do with Firebase making the call on our behalf. Because this codepen, in which we do our own authentication, works fine:
http://codepen.io/morgs32/pen/KVgzBw
Don't forget to set clientId and apiKey in the codepen.
If you can figure this one out you're gonna get gold on christmas.

You're trying to use authData.token to access Google. But authData.token is a JWT token for accessing Firebase.
To access Google, you should use authData.google.accessToken.
Also see this page in the Firebase documentation on using the Google provider.

Related

How to create SendBird user with SendBird Platform API and Request node library

We are building a react-native chat app. We are implementing a back end authentication solution on google Firebase. The creation of a new user in Firebase Auth triggers a cloud function which should create a new SendBird user with an access token. The access token will be stored in Cloud Firestore, ready for retrieval the next time the user logs in.
We are having trouble implementing the POST request that creates the new user via the platform API. We are using the Request library for node.js. We are able to reach the API endpoint, but the following object is returned: { message: 'SendBird API Endpoint.', error: true }. There is no indication of what the error may be.
This happens when sending the request to the base url. When we send the request to /users or /v3/users, we receive a 403 error.
Any indication as to what may be causing this problem would be greatly appreciated.
Below is the cloud function index.js code
const functions = require('firebase-functions');
const admin = require("firebase-admin");
const request = require('request');
admin.initializeApp();
exports.handleNewUser = functions.auth.user().onCreate((user) => {
var newUserRequestBody = {
"user_id": user.email,
"nickname": user.email,
"profile_url": "",
"issue_access_token": true,
}
request.post({
headers: {
'Content-Type': 'application/json, charset=utf8',
'Api-Token': // API Token
},
url: 'https://api-{application_id}.sendbird.com',
form: newUserRequestBody
}, function(error, response, body){
if (!error && response.statusCode === 200) {
const info = JSON.parse(body);
console.log("request successful");
console.log(response.statusCode);
console.log(info);
}
else{
console.log("request unsuccessful");
console.log(response.statusCode);
console.log(error);
}
});
return null;
});
Did you try with full path of end point to url: (including /v3/users)?
Or you may need to use "baseUrl" like below?
https://github.com/request/request#requestoptions-callback
Also, you need to make sure that you correctly used {application_id} value and {API Token} value.
You can double check this from your dashboard of SendBird.
http://dashboard.sendbird.com > Log in with your ID > select your APP.
There is a section named "App credentials" in "Overview" menu.
You can double check your API-request URL and API-Token value from there.

Is there a way to link the Google Identity Token to my company user in the database?

I'm setting up an action on google project which uses the OAuth & Google Sign In Linking Type.
Previously, I was using the userId that was sent in every request to look up the user in the database to see if there were accesstokens and refreshtokens available. But since userId is deprecated, I am looking for an alternative.
The user starts his/her dialog and then bumps into this piece of code:
app.intent('Give Color', async (conv, { color }) => {
conv.data[Fields.COLOR] = color;
if (conv.user.ref) {
await conv.user.ref.set({ [Fields.COLOR]: color });
conv.close(`I got ${color} as your favorite color.`);
return conv.close('Since you are signed in, I\'ll remember it next time.');
}
return conv.ask(new SignIn(`To save ${color} as your favorite color for next time`));
});
The "To continue, link Test App to your Google Account" on which the user selects the correct Google account.Then my /token endpoint is called on the OAuth server containing the Google ID Token (assertion) which holds all of the users data. I decode it, check in the database if the "sub" is already present, and I throw the following exception:
return res.status(401).send({ error: 'user_not_found' });
Then the normal OAuth procedure kicks in, where I deliver a token to Google. Sidenote: this is my own OAuth Server written in NodeJS. I am sure that the access- and refreshtoken are delivered to Google.
After token delivery, I get a new request on my action:
app.intent('Get Sign In', async (conv, params, signin) => {
if (signin.status !== 'OK') {
return conv.close('Let\'s try again next time.');
}
const color = conv.data[Fields.COLOR];
await conv.user.ref.set({ [Fields.COLOR]: color });
return conv.close(`I saved ${color} as your favorite color. `
+ 'Since you are signed in, I\'ll remember it next time.');
});
The signin.status has a value of "OK". But shouldn't the conv.user object contain the Google ID Token so that I can store the access- and refreshtoken along with this "sub" from the Google ID Token in my database? Or am I getting something wrong?
The content of the conv.user looks like this:
User {raw: Object, storage: Object, _id: undefined, locale: "en-BE", verification: "VERIFIED", …}
_id: undefined
[[StableObjectId]]: 7
access: Access {token: "ACCT-ATlbRmcpMI545WJFssRSlK1Jcza46NIB"}
entitlements: Array(0) []
id: undefined
last: Last {seen: Thu Aug 08 2019 10:53:17 GMT+0200 (Central Europea…}
locale: "en-BE"
name: Name {display: undefined, family: undefined, given: undefined}
permissions: Array(0) []
profile: Profile {token: undefined}
raw: Object {accessToken: "ACCT-ATlbRmcpMI545WJFssRSlK1Jcza46NIB", locale: "en-BE", lastSeen: "2019-08-08T08:53:17Z", …}
storage: Object {}
verification: "VERIFIED"
__proto__: Object {constructor: , _serialize: , _verifyProfile: , …}
conv.user.id is *DEPRECATED*: Use conv.user.storage to store data instead
It won't contain the Google ID of the user, because the user hasn't authorized that.
What they have authorized is whatever you've asked them to authorize via your OAuth server.
So you'll see the access token that your server has sent to the Assistant in conv.user.access, and you can then use this token to lookup who the user is in your database and take action accordingly.
If you specifically want their Google ID, you'll need to make sure that they use Google Sign-In on the same project as your Action (either through voice, a mobile app, or a webapp).
If you just need an ID so you can see when this user returns later, you can use the Google ID you get from Google Sign-In, or just generate an ID and store this in conv.user.storage.
Since I just want to have an ID, I will be using this:
If you just need an ID so you can see when this user returns later, you can use the Google ID you get from Google Sign-In, or just generate an ID and store this in conv.user.storage.
Thanks!

invalid_grant on OAuth2 request when obtaining access_token from SSO in App

I have an iOS App with an Uber API integration where I use SSO to authenticate the user and then save the accessToken & refreshToken locally on my device. Then I'm calling my server who uses a javascript background function to call the node-uber (https://www.npmjs.com/package/node-uber) library to make a request to Uber.
So far, I'm trying to set up the uber client with my 2 local tokens from the SSO login like this:
var uber = new uberClient({
client_id: '...',
client_secret: '...',
server_token: '...',
name: 'My App',
sandbox: true, //optional
access_token: accessToken,
refresh_token: refreshToken
});
afterwards I want to call the uber.requests.getEstimatesAsync endpoint like this:
uber.requests.getEstimatesAsync({
"start_latitude": pickupLocation["lat"],
"start_longitude": pickupLocation["lng"],
"end_latitude": dropoffLocation["lat"],
"end_longitude": dropoffLocation["lng"]
})
.then(function(res) {
console.log(JSON.stringify(res));
})
.error(function(err) {
console.error(err);
});
})
Though every time I get an "invalid_grant" error 400 while doing this. Did I make a mistake authenticating myself or setting up the Uber client wrong? Is it even possible to use my SSO accessToken & refreshToken then on the uber client, which does a OAuth2 authentification? I thought that both access and refresh token should probably be the same what Uber sends back to be for SSO & OAuth2.
I'm using a Developer account for doing this, therefore I should actually have all the required permissions for the request endpoint, but I also obtained them previously in the App correctly.
This thread on the official uber documentation explains potential reasons but I guess they don't really apply to my case, do they? https://developer.uber.com/docs/riders/guides/authentication/introduction#common-problems-and-solutions
Any security expert here who can help?
Best regards,
Matt
P.S.: I also posted this question on the Uber library I'm using for making those requests, but nobody seems to be able to help me there so far. https://github.com/shernshiou/node-uber/issues/70
Edit: The following picture shows my authentication setup so far:
I found a solution. I think was a problem with the library itself. Because once I made the request with http with the "request" library (https://github.com/request/request) it worked. Include for that at the top of your code:
var request = require('request');
Both OAuth2 and SSO accessToken worked. You should give the method a pickupLocation with latitude and longitude and your obtained accessToken from Uber like this:
function getAllAvailableUberProducts(pickupLocation, accessToken){
var lat = pickupLocation["lat"].toString();
var lng = pickupLocation["lng"].toString();
var options = {
uri: "https://api.uber.com/v1.2/products?latitude="+lat+"&longitude="+lng,
method: 'GET',
headers: {
"Authorization": "Bearer " + accessToken,
"Accept-Language": "en_US",
"Content-Type": "application/json"
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(JSON.parse(body).products);
} else {
console.log(error);
}
});
}
I hope this helps someone.

can't get access token using refresh token

I wrote desktop application on java, which have access to the Google drive. (it just uploads and downloads files).
At the moment access type is online. when I need to access files/folders to the drive, I
redirect he browser to a Google URL and get access code:
String code = "code that was returned from brouser"
GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
everything works well! but I need to have that redirection only first time.
When I google, in the Google Drive API documentation I found that I can get refresh token via browser redirection and save it on DB for instance. (In the other word, I can use offline access).
And every time when I need to read data from google drive, I get access token using refresh token without redirection. is not it?
so I get refresh token like that:
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=695230079990.apps.googleusercontent.com&scope=https://www.googleapis.com/auth/drive&response_type=code&redirect_uri=https://localhost
question 1
I get code, from the browser redirecting. it's refresh token, is not it?
now, I need to get access token using that refresh token.
$.ajax({
type: "POST",
url: 'https://accounts.google.com/o/oauth2/token',
data: {
client_id: "695230079990.apps.googleusercontent.com",
client_secret: 'OWasYmp7YQ...4GJaPjP902R',
refresh_toke: '4/hBr......................xwJCgQI',
grant_type: 'refresh_token'
},
success: function(response) {
alert(response);
}
});
but I have error 400;
question 2) when I try to change redirect url I have that error: *
Invalid parameter value for redirect_uri: Non-public domains not allowed: https://sampl.ecom
so, must I create web applications Client ID , instead of installed application from google APIs console? Can't I change Redirect URI in installed application? I'm confused, I don't know, which should I use.
1) when you try to have offline access, you get authorization code which may be redeemed for an access token and a refresh token.
For isntance:
https://accounts.google.com/o/oauth2/auth?access_type=offline
&approval_prompt=auto
&client_id=[your id]
&redirect_uri=[url]
&response_type=code
&scope=[access scopes]
&state=/profile
after you get authorization code, you cat get refresh token.
static Credential exchangeCode(String authorizationCode)
throws CodeExchangeException {
try {
GoogleAuthorizationCodeFlow flow = getFlow();
GoogleTokenResponse response =
flow.newTokenRequest(authorizationCode).setRedirectUri(REDIRECT_URI).execute();
return flow.createAndStoreCredential(response, null);
} catch (IOException e) {
System.err.println("An error occurred: " + e);
throw new CodeExchangeException(null);
}
}
See the section on Implementing Server-side Authorization tokens for more information.
and after you get refresh token , you must save it. see that sample for mor information.
2) If you don't have installed application, you should create web applications to change redirecting URL.

Twitter message post in Titanium

I got some code by doing search which is doing a lot for me in showing the my tweets in tableview,till now fine. I want to add one more functionality to it that user can post the message from the sameapp.
So I just modified the code as per. While I hit the request I got result status as successful but message is not posting to my wall. I have all keys and getting access token as well.
var client = Twitter({
consumerKey: "have Key ",
consumerSecret: "have Key",
accessTokenKey: accessTokenKey,
accessTokenSecret: accessTokenSecret
});
client.request("1/statuses/update.json", {status:'TEST'}, 'GET', function(e) {
if (e.success) {alert(e.success);
} else {
alert(e.error);
}
Updated: I have go through the Twitter Dev API
This is the URL http://api.twitter.com/1/statuses/update.format with required parameter "status". What am I doing wrong?
You are sending GET request to update status whereas twitter api needs it to be a POST request.
Try something like
client.request( "1/statuses/update.json", {status:'TEST'}, 'POST', function(e) {
if (e.success)
{
alert(e.success);
} else {
alert(e.error);
}
Check out this application: https://github.com/appcelerator-titans/tweetanium
From what I understand this is a fully working example of a twitter app created using Titanium Mobile. Perhaps you can follow the logic in here and see where you need to adjust.

Resources