DialogFlow Webhook API V2 - How to get Authorized User's accessToken? - actions-on-google

In my DialogFlow V1 Webhook, I used to get the user's access token like this (node.js):
exports.voxGoogleHomeWebhook = functions.https.onRequest((req, res) => {
const app = new WebhookClient({request: req, response: res});
var accessToken = app.getUser().accessToken
This does not work in DialogFlow V2. getUser() is not available on instance of WebhookClient.
I can not find in their documentation, how to get the accessToken of the Logged In user:
https://dialogflow.com/docs/fulfillment
I tried getting app.session, but that's just the unique session string Identifier of the user's session. It's not their access token.
How can I get the accessToken in V2?

It looks like the portion of the request object that contains this info isn't (yet) handled by the library. I've opened a bug on the issue, and you may wish to follow or comment on it.
In the meantime, you can access the user information by looking at the req.body object. Specifically you can look at req.body.originalDetectIntentRequest.payload.user to get the User object. The accessToken field there is the one you're looking for.

Related

Get facebook user profile image after facebook changes(October 24)

So facebook changed the way websites get the user profile image, all the details are here:
https://developers.facebook.com/docs/graph-api/reference/user/picture/
So me and also SOF get the profile image of a user from facebook like this:
https://graph.facebook.com/1108834579148558/picture?type=large
Now we get the default image facebook provides.
In facebook docs they write we need to attach Access Token in order to get the user profile image from now, How does it work?
The only thing I can think of is upon user login facebook can retrieve the user profile image, does anyone can help with this, I am using .Net core.
Facebook explains the new way of getting the User Image after October 2020 in their new docs here and they state the required changes as following:
This endpoint supports App-Scoped User IDs (ASID), User IDs (UID), and Page-Scoped User IDs (PSID). Currently you can query ASIDs and UIDs with no requirements. However, beginning October 24, 2020, an access token will be required for all UID-based queries. If you query a UID and thus must include a token:
1. Get an access_token in any form that facebook provides you
Depending on your application structure you would use either one of the following methods provided by Facebook to gain an access_token. You can find more about access_token on the FB docs here.
App Access Token
Client Access Token
As an Example for the Client Access Token which I am using:
Make a GET Request to https://graph.facebook.com/oauth/access_token with the following parameters:
[
"client_id" => #FACEBOOK_CLIENT_ID,
"client_secret" => #FACEBOOK_CLIENT_SECRET,
"grant_type" => "client_credentials",
]
As Response you will get your access_token which you need to attach on the new Image URL.
2. Get the full avatar URL with the access_token attached.
As of 2020 October 23 this is working for me.
The Full Image format is now
{$this->graphUrl}/{$this->version}/{$userID}/picture?type=large&redirect=false&access_token={$access_token}
If you set redirect=false you will get a JSON Object as Response:
{
"data": {
"height": 100,
"is_silhouette": false,
"url": "https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=10152700727498624&height=100&width=100&ext=1606081666&hash=AeTQyGgugiSbRcB7Sxw",
"width": 100
}
}
In the other hand if you leave redirect=true or doesn't set it at all you will get the Image itself which you can then save on your disk or use the url as the image path. But I am not sure if that given URL is long lived or not. I got the same URL working for almost one Week now, so I think that URL will stay as it is once you have requested for it with an valid access_token.
Example Request in PHP
As I have implemented that in PHP I cannot give you an example code but show you the way I've done it with the Guzzle Client within the Laravel Framework. You can have a look into my upgraded Provider Class for Laravel Socialite here.
public function getAccessToken(){
// Make a request to get the Access Client
$res = Http::get("https://graph.facebook.com/oauth/access_token", [
"client_id" => config('services.facebook.client_id'),
"client_secret" => config('services.facebook.client_secret'),
"grant_type" => "client_credentials",
]);
// Response is a JSON Object, so decode it into an Array
$r = $res->json();
// Return the access_token Array Key out of the response
return Arr::get($r, 'access_token', false);
}
public function getFacebookAvatar(array $user){
// get the access_token from the above method
$access_token = $this->getAccessToken();
// build the new URI path for the User Image
$path = "{$this->graphUrl}/{$this->version}/{$userID}/picture?type=large&redirect=false&access_token={$access_token}";
$res = Http::get($path);
// Get the final User Image URL out of the response
return Arr::get($res->json(), 'data.url', false);
}
Quick and dirty way to build your own Access Token (not recommended)
There is one way to build your own access_token but this should be used only for testing purposes due the fact you are providing your full credentials and that could be hijacked. You can archieve that by building a concatened string with your credentials and the | as delimiter in this format: {cliend_id}|{client_secret}.

Azure App Service Facebook

I've migrated from Azure Mobile Service to an App Service but I'm having difficulty working out how best to implement extended Facebook auth.
In my old implementation I inherited from FacebookLoginProvider and fetched the token from the claims. I then added the CustomFacebookLoginProvider to my login providers. I then use the token to fetch more information about the user (their date of birth, friends and gender). With this information I created a user object and saved it to my DB.
Does anyone have any suggestions on how best to recreate this in App Service as I can't find any documentation.
As far as how to set up Facebook authentication, you can find documentation here (and it sounds like you've already figured out this much):
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-how-to-configure-facebook-authentication/
Now that Facebook authentication is set up, you can refer to the following which shows how to obtain user information:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-dotnet-backend-how-to-use-server-sdk/#user-info
// Get the credentials for the logged-in user.
var credentials =
await this.User
.GetAppServiceIdentityAsync<FacebookCredentials>(this.Request);
if (credentials.Provider == "Facebook")
{
// Create a query string with the Facebook access token.
var fbRequestUrl = "https://graph.facebook.com/me?access_token="
+ credentials.AccessToken;
// Create an HttpClient request.
using (var client = new System.Net.Http.HttpClient())
{
// Request the current user info from Facebook.
using (var resp = await client.GetAsync(fbRequestUrl))
{
resp.EnsureSuccessStatusCode();
// Do something here with the Facebook user information.
var fbInfo = await resp.Content.ReadAsStringAsync();
}
}
}
Note that you must add a using statement for System.Security.Principal to make the GetAppServiceIdentityAsync extension method work.
For more information on which Facebook user properties you can query, see the Facebook documentation here: https://developers.facebook.com/docs/graph-api/reference/user. Note that you may need to specify which user properties you want as an additional fields query string parameter on your call to the Facebook graph.
The only change I had to make when switching from Mobile Service to Mobile App was to change the end of the callback URL in the developer portal to use /.auth/login/facebook/callback instead of /signin-facebook and it worked exactly the same way as before.
Note that this is for a Windows app with a .NET backend; you didn't specify what you're using so your mileage may vary.
I've been using the following approach to obtain the Facebook Access Token in the iOS app.
App Services includes the Facebook Access Token in the request header, refer to https://azure.microsoft.com/en-in/documentation/articles/app-service-api-authentication/.
To get to the access token, create a Custom API in the Azure Portal, e.g. facebookUserInfo, with the following code:
module.exports = {
"get": function (request, response, next) {
response.send(200, { facebookAccessToken: request.headers['x-ms-token-facebook-access-token'] });
}};
In the iOS app, use the following code to query the custom API:
let client = self.table!.client
if client.currentUser != nil {
client.invokeAPI("facebookUserInfo", body: nil, HTTPMethod: "GET", parameters: nil, headers: nil, completion: { (result, response, error) -> Void in
if let resultDict = result {
if let facebookAccessToken = resultDict["facebookAccessToken"]! {
print(facebookAccessToken)
}
}
}
}
By Using the Easy Auth feature of Azure App Services, I dont need to worry about authentication.
I have a blogpost on this. I have explained on how we can use the FB GraphApi's to query FB data. Here is the link: https://blogs.msdn.microsoft.com/kaushal/2017/06/08/using-easy-auth-to-query-facebook-information-via-graph-api/
I have the sample code deployed on Github. Here is the link: https://github.com/kaushalp/Facebook-GraphApi-with-EasyAuth

Google OAuth API to get user's email address?

I am playing with Google's OAuth 2.0 Playground using my own personal Google account, but I cannot seem to recover my Gmail address using the playground.
The scope I am using is:
email profile https://www.googleapis.com/auth/plus.login
But when I call the API:
https://www.googleapis.com/oauth2/v2/userinfo
I get various information about the user such as family name, first name, gender, picture, etc. but it does not return the user's email.
How do I retrieve the user's email address? Do I have the wrong scope or am I calling the wrong API? I feel like this should be very simple but I have literally been trying to figure this out for hours and I cannot find an API and scope combination that consistently provides the user's email address.
Update: December 2018
On December 20th, Google announced that the Google+ API would be turned down in March 2019, with intermittent failure starting at the end of January 2019. As part of the the plus.people.get endpoint is deprecated and scheduled to be terminated.
The userinfo endpoint is de-deprecated (see clarification) and should provide the info assuming
You request the https://developers.google.com/identity/sign-in/web/devconsole-project scope and
You request the email field.
Clarification: 24 Jan 2019
Google documented that the userinfo (v2) endpoint was deprecated, but later changed it to "deprecated, but kept available for backwards compatibility".
Current documentation discusses getting profile and email information through the currently supported openid method. This includes using the "userinfo" endpoint specified in their discovery document, as required by OpenID Connect.
At the moment, that URL is https://openidconnect.googleapis.com/v1/userinfo, but this has changed in the past and the discovery document at https://accounts.google.com/.well-known/openid-configuration is the authoritative source for the URL to use.
So, to be clear:
The old userinfo URL is maintained for backwards compatibility
The new userinfo URL is available at the discovery document
Regardless, the plus version of anything (described below) is deprecated and scheduled to be removed.
Original Answer
There are a lot of issues here in what you're doing and how you're trying to do it.
For starters, the https://www.googleapis.com/oauth2/v2/userinfo endpoint is deprecated, and scheduled to be removed in September 2014. It has begun working inconsistently - so don't use it.
As #abraham noted, you'll use the people.get endpoint at https://www.googleapis.com/plus/v1/people/me. This should give you the emails field containing an array of addresses. In your case, there will likely be only one that has a type of "account".
As of 2017: use the email scope. See Authorizing API requests.
This email scope is equivalent to and replaces the
https://www.googleapis.com/auth/userinfo.email scope.
For signing in with Google using OAuth 2.0, there's no need to make a separate request to get user's email.
When Google calls the callback URL, it provides a code in the query string that you could use to exchange for access token and ID token. The ID token is a JWT that contains identity information about the user, which includes the email address.
See more information here: https://developers.google.com/identity/protocols/oauth2/openid-connect
You'll want to add the https://www.googleapis.com/auth/userinfo.email scope or replace https://www.googleapis.com/oauth2/v2/userinfo with it. If you're using the HTML example they provide, you can list multiple scopes separated by a space.
<span
class="g-signin"
data-callback="signInCallback"
data-clientid="{{ plus_id }}"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login
https://www.googleapis.com/auth/userinfo.email">
</span>
To retrieve the email address, you need to include the scope: "https://www.googleapis.com/auth/userinfo.email" as mentioned in this document. If this scope is included while you generate the refresh token, you should be able to get the email address of the authenticating user by making the following request:
you can call this with your own access token then will give the response
https://www.googleapis.com/oauth2/v3/userinfo?access_token="YOUR_ACCESS_TOKEN"
response will look like this
{
"sub": "1057abc98136861333615xz",
"name": "My Name",
"given_name": "My",
"family_name": "Name",
"picture": "https://lh3.googleusercontent.com/a-/AOh14qiJarwP9rRw7IzxO40anYi4pTTAU_xseuRPFeeYFg",
"email": "MyName#gmail.com",
"email_verified": true,
"locale": "en"
}
or simply you can just write a function
import requests
def get_user_email(access_token):
r = requests.get(
'https://www.googleapis.com/oauth2/v3/userinfo',
params={'access_token': access_token})
return r.json()
I came here looking why my server did not get email in response to /oauth2/v2/userinfo api call. It was only once that I saw this & it has been working well in past.
The answer gave good lead. While fixing this, there were several other resources that helped. Still I am not sure whether expecting always email in the response is ok. so - put error handling in code in case emails are not returned.
Google api documentation about migrating to google+ signin.
https://www.googleapis.com/auth/userinfo.email scope
People resource documentation
Add google+ api to the project using google developer console. The complimentary (quota) of calls is quite high (20m for google+ signin api per day).
Add error handling & logging in server code in case api returns no emails. In my case, I was looking only type='account' email.
This is actually a bit of a challenge as Google does not provide an email by default. You must specifically request it from Google Plus.
const scope = [
'https://www.googleapis.com/auth/plus.me', // request access here
'https://www.googleapis.com/auth/userinfo.email',
];
auth.generateAuthUrl({
access_type: 'offline',
prompt: 'consent',
scope: scope,
});
const plus = google.plus({ version: 'v1', auth });
const me = await plus.people.get({ userId: 'me' });
const userEmail = me.data.emails[0].value;
There is a full version in this blog post I wrote: https://medium.com/#jackscott/how-to-use-google-auth-api-with-node-js-888304f7e3a0
by using google nodejs sdk:
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
googleClientIdPublic,
googleClientSecret,
googleRedirectUriPublic
);
//scope you need: https://www.googleapis.com/auth/userinfo.email
oauth2Client.setCredentials(tokens);
const googleAuth = google.oauth2({
version: "v2",
auth: oauth2Client,
});
const googleUserInfo = await googleAuth.userinfo.get();
const email = googleUserInfo.data.email;
more info
I have been following Prisoner's answer right above, and it helped me... until I received the email from Google Developers about how Google+ API will be shutdown on March 7, 2019.
I scrounged around and found this solution to get the email using an id_token that is returned when you authorize an app with the email scope on your developer console.
From Google Sign-in for Websites:
To validate an ID token in PHP, use the Google API Client Library for
PHP. Install the library (for example, using Composer):
composer require google/apiclient
Then, call the verifyIdToken() function. For example:
require_once 'vendor/autoload.php';
// Get $id_token via HTTPS POST.
$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
}
This will return an array that contains the user information, that also contains the email of the user who logged in. Hope this helps anyone else.
Please see my answer here to the identical issue:
how to get email after using google OAuth2 in C#?
In your scopes variable. Use the value "email" not the
full https address. Scope keywords in the web link are separated by spaces. I solve your issue with scopes written as: profile email openid.
https://developers.google.com/gmail/api/v1/reference/users/getProfile
For gmails api, add this to nodejs code:
function getUsersEmail (auth) {
const gmail = google.gmail({version: 'v1', auth})
gmail.users.getProfile({
userId: 'me'
}, (err, {data}) => {
if (err) return console.log('The API returned an error: ' + err)
console.log(data.emailAddress)
})
}
Gmails api: https://developers.google.com/gmail/api/guides/
Change the authorizationRequest with given scope: scope=openid%20email%20profile and use userinfoapi. This link worked for me
I suggest the following minimal code, which include '*/userinfo.email' and '#google-cloud/local-auth' package:
const path = require('path');
const { google } = require('googleapis');
const { authenticate } = require('#google-cloud/local-auth');
const scope = [
'https://www.googleapis.com/auth/userinfo.email'
];
async function runSample() {
const auth = await authenticate({
keyfilePath: path.join(__dirname, 'oauth2.keys.json'),
scopes: scope
});
google.options({ auth });
const dat = await google.oauth2('v2').userinfo.get()
console.log(dat.data.email);
}
if (module === require.main) {
runSample().catch(console.error);
}
module.exports = runSample;

Validating the user of an access_token

In the Facebook dev article Manually Building a Login Flow, there is a section entitled "Confirming Identity". It mentions that you need to validate codes and tokens that you receive from them via your redirect_uri.
My question: Since you don't know anything about the user that just logged in, how do you validate that the user_id that you see in the response from the token inspection endpoint is correct?
The article says:
As a result, your app should confirm that the person using the app is the same person that you have response data for before generating an access token for them.
But, how can you actually do that? Are we expected to show publicly available info about that user_id back to the user with a UI that asks "Is this you?". I haven't seen any apps/sites that do that, so I'm assuming that this isn't practically done.
Am I missing something?
You can use FB.getLoginStatus to retrieve information about the logged in user. It returns a response object for the user. If the user has authenticated your application, the response object will look like this:
{
status: 'connected',
authResponse: {
accessToken: '...',
expiresIn:'...',
signedRequest:'...',
userID:'...'
}
}
You can use the UserId returned in this object to verify the user's identity.

Facebook access token server-side validation for iPhone app

I'm developing iPhone application, that is based on communication with server, and I want to use Facebook authentication mechanisms.
Basically, I think it should work like this:
In my iPhone app, user logs in to Facebook, using his email and password.
User allows access to his data for related Facebook application.
My iPhone app receives access token, after successful log in.
In further communication with my server, my iPhone application should use the received Facebook access token (for example: in queries).
When my server receives some query from iPhone app, with access token, it should ask Facebook that this token is valid (and for who), and if yes, server should assume that user is authenticated with Facebook.
My question is: how the server should ask Facebook if given access token is valid? I think I should somehow check if the token is valid for my Facebook app.
I've tried many Facebook queries to graph API, that I've found, but nothing worked as I expected. Can you provide me some example?
Here's a two step process you can use to validate that a user access token belongs to your App:
1) Generate an App Access token
(https://developers.facebook.com/docs/howtos/login/login-as-app/)
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&client_secret=YOUR_APP_SECRET
&grant_type=client_credentials
2) Debug the User Access token
(https://developers.facebook.com/docs/howtos/login/debugging-access-tokens/)
https://graph.facebook.com/debug_token?
input_token=INPUT_TOKEN
&access_token=ACCESS_TOKEN
Where INPUT_TOKEN is the user access token you want to verify, and ACCESS_TOKEN is your app's token that you got from step 1.
The debug endpoint basically dumps all information about a token, so it'll respond with something like this:
{
data: {
app_id: YOUR_APP_ID,
is_valid: true,
metadata: {
sso: "iphone-safari"
},
application: YOUR_APP_NAMESPACE,
user_id: USER_ID,
issued_at: 1366236791,
expires_at: 1371420791,
scopes: [ ]
}
}
If that token isn't from "your app" then it will return an error response.
Update: this answer seems insecure since it doesn't validate the token
first as belonging to your app, see the comments, original answer as
follows:
I assume that you already have the access token in hand. In such a case the simplest way to validate an access token is to issue the following request
https://graph.facebook.com/me?fields=id&access_token=#accesstoken
Here replace #accesstoken with the access token you have. I will breakdown the url and will explain each.
We are issuing a graph api request here which will return the Facebook User Id of the owner of the access token as a JSON string. The keyword 'me' represents the currently logged in user or the owner of the access token. For this request access token is a mandatory parameter.
If the provided access token is not valid or expired Facebook will just return an error message of some sort.
For a valid access token the result will somehow look like this
{
"id": "ID_VALUE"
}
Another solution would be to use https://graph.facebook.com/app/?access_token=[user_access_token] as described by Get application id from user access token (or verify the source application for a token).
This appears to be an undocumented feature, but returns JSON containing the id of the app the token was generated for. If the token wasn't for your app, it returns a 400.
In the latest version of facebook (2.2) you can do it this way:
https://developers.facebook.com/docs/graph-api/reference/v2.2/debug_token
Sample output:
{
"data": {
"app_id": "THE APP ID",
"application": "APP NAME",
"expires_at": 1427245200,
"is_valid": true,
"scopes": [
"public_profile",
"basic_info",
"read_stream",
"email",
"publish_actions",
"read_friendlists",
"user_birthday",
"user_hometown",
"user_location",
"user_likes",
"user_photos",
"user_videos",
"user_friends",
"user_posts"
],
"user_id": "THE USER ID"
}
}
private function facebookRequestMe($access_token)
{
include_once "facebook.php";
$facebook = new Facebook(array(
"appId" => "your_application_id",
"secret" => "your_application_secret"
));
$facebook->setAccessToken($access_token);
return $facebook->api("/me", "GET");
}
You can download the Facebook SDK for PHP from GitHub.
If a user has passed you a Facebook UID that they claim is theirs and you want to check if it's legit, this is a Python function that will verify it against their access token (an implementation of Robin Jome's answer):
def verify_facebook_id(id, access_token):
import requests
import simplejson
params = {'fields': 'id', 'access_token': access_token}
text = requests.get("https://graph.facebook.com/me", params=params).text
json = simplejson.loads(text)
response_id = json["id"]
return response_id == id
This is the only secure method to verify user token using just one request:
https://graph.facebook.com/debug_token?input_token={token-to-inspect}&access_token={app_id}|{app_secret}
Note that a sign "|" in the above URL isn't used as OR but as separator and must be there after fill the other fields.
The response will be JSON looking like that:
{
data: {
app_id: {app_id},
application: {app_name},
expires_at: {some_number},
is_valid: {true|false}
scopes: {array_of_permissions},
user_id: {user_id}
}
}
Reference: https://developers.facebook.com/docs/facebook-login/access-tokens/#apptokens
(above method is mentioned at the bottom of this section)
Along with an access token Facebook also sends an "expires_in" parameter, which is an offset value. Use that to compute for when the access token will expire as an NSDate. Then when you need to do a request compare the current date with the expiration date.
Also try to inspect the status codes and response strings Facebook sends back.