DialogFlow v2 Access Token cannot generate - javascript

With version 1 this is how I used to communicate with DialogFlow Api!
fetch(configs.baseUrl + "query?v=20150910", {
body: JSON.stringify({query: text, lang: "en", sessionId: "somerandomthing"}),
headers: {
'content-type': 'application/json',
"Authorization": "Bearer " + configs.accessToken,
},
method: 'POST',
})
.then(response => response.json())
.then(data => {
console.log(data.result.fulfillment.speech);
return data.result.fulfillment.speech;
})
.catch(error => console.error(error))
I simply had to pass the access token into header and that was it!
I dont know how can I make this code work with DialogFlow v2, I am getting stuck on the access token, one my V2 Agents I can not longer see access token but instead I have a Project Id and Service Account.
I manage to create Service key from google console and activate thru gcloud but I just dont know where to get or how to generate this access token, or do I need an access token into v2, if not, how do I deal with this?
A working example would much appreciated.
Note I have downloaded this file which contains these kind of data and used this file in gcloud and it said that service activated smth but then what?
is that all? what should I do next so I can make http call to V2 DialogFlow.
{
"type": "service_account",
"project_id": "xxxx",
"private_key_id": "xxxx",
"private_key": "-----BEGIN PRIVATE KEY-----xxxx",
"client_email": "xxxx",
"client_id": "xxxx",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/dialogflow-client%40xxxx"
}

You did pretty much the right thing, but you would probably want to use Dialogflows Node.js client SDK. These SDKs read the authentication JSON file automatically when you instantiate a client (see the example on Github, the file is read by ... = new dialogflow.SessionsClient()).

Below is another example of creating your DialogFlow V2 access token using Node.js. The library that is used in the code below is google-oauth-jwt.
const googleAuth = require('google-oauth-jwt');
function generateAccessToken() {
 return new Promise((resolve) => {
  googleAuth.authenticate(
   {
    email: <client_email>,
    key: <private_key>,
    scopes: 'https://www.googleapis.com/auth/cloud-platform',
   },
   (err, token) => {
    resolve(token);
   },
  );
 });
}
You may find your client_email and private_key from the JSON key file you have downloaded from your Google Cloud Platform project's service account page. If you are unsure how/where to download it, you may checkout my blog post here.
To find out which scope which scope you may need, you may checkout the DialogFlow V2 REST API documentation page.

You might be interested in this:
https://cloud.google.com/docs/authentication/api-keys

Related

Getting an authentication token for a Microsoft Custom App

I have been struggling with the same issue for a while now, i'm trying to upload a file to my MS Teams OneDrive through the Graph-API but i dont have the authorization for it.
Reading the documentation to get my Token from Microsoft has so far done nothing for me as i am new to Javascript and React, so im having extreme difficulty getting it to work right. Can anyone give me an example of what the code looks like to get the authorization token that i need to access the Graph-API?
I have registered my Microsoft app and made a client-secret that i need in order to fetch the token.
Thank you in advance!
My code:
import React from 'react';
import './App.css';
import * as microsoftTeams from "#microsoft/teams-js";
class Tab extends React.Component {
constructor(props){
super(props)
this.state = {
context: {}
}
}
componentDidMount() {
var myHeaders = new Headers();
myHeaders.append("Content", "text/plain");
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Authorization", "Bearer {token}");
var raw = "This works";
var requestOptions = {
method: 'PUT',
headers: myHeaders,
body: raw,
redirect: 'follow'
}
fetch("https://graph.microsoft.com/v1.0/sites/OpenSesameTest/Shared%20Documents/General/FileB.txt:/", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
componentDidMount() {
var myHeaders = new Headers();
myHeaders.append("Content", "text/plain");
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Authorization", "Bearer {token}");
var raw = "Fetch my token";
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
}
fetch("https://login.microsoftonline.com/openimstest/oauth2/v2.0/c7094fc6-9d30-429d-bb66-dd389295b426", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
render() {
return (
<form>
<div>
<label>Select file to upload</label>
<input type="file"></input>
</div>
<button type="submit">Upload</button>
</form>
);
}
}
export default Tab;
P.S.
I know im not actually using teh file input on my page but i want to do it as simple as possible at first, i'll be happy just to succesfully upload a file through the Graph-API at the moment.
Once again thank you!
EDIT:
The the fetch im trying to use in order to get the token:
componentDidMount() {
var myHeaders = new Headers();
myHeaders.append("Content", "text/plain");
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Authorization", "Bearer <token>");
var raw = "This works";
var requestOptions = {
method: 'GET',
grant_type: 'Unsure where to find my client_credentials',
client_id: 'my client-id',
scope: 'https://graph.microsoft.com/.default',
client_secret: 'my client-secret',
headers: myHeaders,
body: raw,
redirect: 'follow'
}
fetch("https://login.microsoftonline.com/openimstest/oauth2/v2.0/token", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
Im unsure where to find my client_credentials or what to put there. Also there is probably something else wrong with the fetch im trying to use.
Microsoft has made a library specially for getting tokens in single pages apps. It’s called #azure/MSAL-browser They even made a package specially for react. msal-react this page shows a getting started on how to use this in react. This package will handle the token request for you.
No client credentials flow
You can do this using client secret by following the steps below. Before you continue, Note that you should not be be using the client credentials flow on the SPA Reactjs application because there is no way to secure the client secret.
The other answer should had left it with this statement. Let me explain that. The client credentials flow is for application that run server side without user interaction. Anyone using this flow in a client app is using it incorrectly! So I’m my opinion we should not educate people in how it might be possible to misuse an authentication flow.
Have a look at this Single sign-on (SSO) support for tabs.
Follow document for creating app registration and setting up expose an API part.
Add route for all these file in your app. You might use the same route as mention in the app I shared below for folder structure.
<Route exact path="/signin" component={SignInPage} />
<Route exact path="/signin-simple-start" component={SignInSimpleStart} />
<Route exact path="/signin-simple-end" component={SignInSimpleEnd} />
Next have a look at this folder structure-> signin. Here you will see three files
sign-in.tsx -> This file route, you need to give in the manifest. It has the button that starts the authentication flow. Also in this file only, you need to give the route of the page you want to show when authentication is successful.
successCallback: () => {
history.push("/yourPage");
}
sign-in-start.tsx -> Here you need to call the authentication endpoint. So in the app that I shared we have backend with C# and from there we get the URL endpoint on the line 22 and push it in history. What you can do is you can directly create that URL(see below) and assign it to variable result(replacing the code from line 22 to 24 with this).
var result = https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize?client_id=<client_id>&response_type=id_token token&redirect_uri=https://<app-domain>/signin-simple-end&response_mode=fragment&scope=<required-scope>&state=12345&nonce=abcde&login_hint=<user-principal-name>;
document.location.href = result;
sign-in-end.tsx -> In this file we get all the token that we have asked in the last step. So, in order to get access token you need to add this code
if (hashParams["access_token"]) {
localStorage.setItem("auth.result", JSON.stringify({
accessToken: hashParams["access_token"]
}));
}
in useEffect where we are getting other tokens. The above code checks if we get the access_token and set it in localStorage later on you can get it with localStorage.getItem("auth.result").
You might need to do little manipulation on localStorage.getItem("auth.result") in order to get the token.
Above method get us the delegated Graph API permission, so you need to give the delegated permission in your app according to your graph call.
You can do this using client secret by following the steps below.
Before you continue, Note that you should not be be using the client credentials flow on the SPA Reactjs application because there is no way to secure the client secret.
Note that If you have to use client secret there then you should remove the interaction with Graph to the serve side and then secure your app using some other way see - this Tutorial: Call the Microsoft Graph API in a Node.js console app for Nodejs Secured Daemon Service authentication
For getting access token using Client Secret.
Add the required application permission on Azure AD for uploading the file to onedrive. In this case Files.ReadWrite.Al. This permission will require admin approval.
Acquire an access token from Azure AD using the request below in fetch format.
curl --location --request GET 'https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token'
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'grant_type=client_credentials'
--data-urlencode 'client_id=client-id'
--data-urlencode 'scope=https://graph.microsoft.com/.default'
--data-urlencode 'client_secret=client-secret'
As I said, client secret will not be secure when used in the Single Page Reactjs application.
The better option is to use auth code flow which will be more secure in your SPA case. Follow this for reactjs Tutorial: Sign in users and call the Microsoft Graph API from a React single-page app (SPA) using auth code flow
This will just require:
Adding Files.ReadWrite as delegated permission on AAD
Signing in with a user that has access to the teams team and authenticating as them.
Call PUT /groups/{group-id}/drive/items/{item-id}/content where the group id is the team id.

Use git credential manager to fetch azure devops api instead of personal access token

I am trying to fetch git azure devops api to get information about repositories and branches in js.
In order to achieve that, I made a little application with the following code :
$(document).ready(function() {
var personalToken = btoa(':'+'<personnalAccessToken>');
fetch('https://dev.azure.com/<company>/<project>/_apis/git/repositories?api-version=5.1', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
'Authorization': 'Basic '+ personalToken
}
}).then(function(response) {
return response.json();
}).then(function(repositories) {
console.log("There are "+repositories.count+" repositories");
}).catch(function(error) {
console.log('Fetch error: ' + error.message);
});
This code is working great but as you can see there is my personnalAccessToken writen directly inside the code... which is really bad...
When I am using git in command line, I don't have to specify any credential information because I use git credential manager for windows. Which means my personnalAccessToken is already stored, cached and automatically used everytime I use a git command, like clone, etc.
So, I would like my js code to use the same thing, I would like it to use my stored credentials automatically to fetch the api without being required to set my personnalAccessToken in code.
I have already searched for hours but can't find out if it is possible.
I have already searched for hours but can't find out if it is
possible.
Sorry but as I know it's impossible. The way you're calling the Rest API is similar to use Invoke-RestMethod to call rest api in Powershell.
In both these two scenarios, the process will try to fetch PAT for authentication in current session/context and it won't even try to search the cache in Git Credential Manager.
You should distinguish the difference between accessing Azure Devops service via Rest API and by Code:
Rest API:
POST https://dev.azure.com/{organization}/{project}/{team}/_apis/wit/wiql?api-version=5.1
Request Body:
{
"query": "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] = 'Task' AND [State] <> 'Closed' AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc"
}
Corresponding Code in C#:
VssConnection connection = new VssConnection(new Uri(azureDevOpsOrganizationUrl), new VssClientCredentials());
//create http client and query for resutls
WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
Wiql query = new Wiql() { Query = "SELECT [Id], [Title], [State] FROM workitems WHERE [Work Item Type] = 'Bug' AND [Assigned To] = #Me" };
WorkItemQueryResult queryResults = witClient.QueryByWiqlAsync(query).Result;
Maybe you can consider using a limited PAT, limit its scope to Code only:
I know there exists other Authentication mechanism
:
For Interactive JavaScript project: ADALJS and Microsoft-supported Client Libraries.
You can give it a try but I'm not sure if it works for you since you're not using real Code way to access the Azure Devops Service... Hope it makes some help :)
If you have the script set up in an Azure Runbook you can set it as an encrypted variable there and have it pull it from there before running rather than having it directly written into the code.
$encryptedPatVarName = "ADO_PAT"
$adoPat = Get-AutomationVariable -Name $encryptedPatVarName
$adoPatToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($adoPat)"))
$adoHeader = #{authorization = "Basic $adoPatToken"}
The above is the Powershell version of it. I have seen some people do it with other

How to get OAuth token from ebay API using express, node, javascript

What combination of requests and responses are needed to get an Oauth token from eBay? What is a runame and what headers do I need to keep eBay happy?
After three frustrating days of trying to get Ebay's oauth to give me an access token, I have finally worked it out. As the docs are pain and there is little to no help online, I have decided to post my solution here in the hope that it will help others. I am no good at StackOverflow so let me know if I need to improve my formatting.
app.get("/login/ebay", (req, res) => {
res.redirect(`https://auth.sandbox.ebay.com/oauth2/authorize?client_id=DeanSchm-TestApp-SBX-b843acc90-fd663cbb&redirect_uri=Dean_Schmid-DeanSchm-TestAp-kqmgc&response_type=code`
);
});
The first thing you need to do is redirect to this URL.
The format is like this
https://auth.sandbox.ebay.com/oauth2/authorize?client_id=&redirect_uri=&response_type=code
There is also a scope property, but I don't understand that yet, and I got back a token without is so me.
That URL takes you to the eBay login page. If you are using the sandbox, you need to create a sandbox user and login with sandbox credentials.
Once you log in, eBay will redirect you to a URL of your choosing. You enter the URL you want to be redirected to here.
It's in the ebay developer section under Get A Token From Ebay Via your Application.
This URL can be anything. you just have to handle it in node or express or whatever, because as soon as someone signs in that URL is where they are heading.
Here is how I handled it
app.get("/auth/ebay/callback", (req, res) => {
axios("https://api.sandbox.ebay.com/identity/v1/oauth2/token", {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization:
"Basic " +
btoa(
`client public key:client secret keys`
)
},
data: qs.stringify({
grant_type: "authorization_code",
// parsed from redirect URI after returning from eBay,
code: req.query.code,
// this is set in your dev account, also called RuName
redirect_uri: "Dean_Schmid-DeanSchm-TestAp-kqmgc"
})
})
.then(response => console.log(response))
.catch(err => console.log(err));
});
A few gotchas that got me.
Make sure you have space after "Basic " in the authorisation
header.
bota is a 3rd party library that base 64 encodes your public and
secret keys. There are many ways to do this. I just did it this way because I stole a bunch of code.
With Axios, the request body is called data but with fetch and other
methods it might be called something else like body or param
The Axios method is in a get request because of the redirect from ebay
defaults to an http get.
ebay now uses https. Make sure you are using
sandbox URLs
We also had to use JS for the eBay API and solved your mention problem with developing a new Lib. It's available here. This lib will also automatically try to refresh the token if it's expires.
This is how we obtain the oAuth token:
import eBayApi from 'ebay-api';
const eBay = new eBayApi({
appId: '-- or Client ID --',
certId: '-- or Client Secret',
sandbox: false,
siteId: eBayApi.SiteId.EBAY_US,
ruName: '-- eBay Redirect URL name --' //in this case: Dean_Schmid-DeanSchm-TestAp-kqmgc
});
// This will generate the URL you need to visit
const url = eBay.oAuth2.generateAuthUrl();
// After grant access, eBay will redirect you to RuName page and set the ?code query.
// Grab the ?code and get the token with:
eBay.oAuth2.getToken(code).then((token) => {
console.log('Token', token);
ebay.oAuth2.setCredentials(token);
// Now you can make request to eBay API:
eBay.buy.browse.getItem('v1|382282567190|651094235351')
.then(item => {
console.log(JSON.stringify(item, null, 2));
})
.catch(e => {
console.log(e);
});
});
Another example with scope can we found here.
Some hints:
with "scope" you tell eBay what you plan to use. You can find the
Descriptions here, under Sandbox/Production Keys Box. (OAuth
Scopes)
if you use axios you can use the auth config, so you dont't
need btoa:
axios("https://api.sandbox.ebay.com/identity/v1/oauth2/token", {
// ...
auth: {
username: 'appId',
password: 'certId'
}
});
To use sandbox without https, e.g. localhost, you can setup a redirect on a https site and redirec/pass the code to non-https site.

Microsoft Graph API token validation failure

I would use Microsoft Graph API in my Angular Web application.
First I make connexion using msal library
When I try log in with my profil I get this error
I have configured my app as the mentionned in the official git sample
MsalModule.forRoot({
clientID: "Tenant ID",
authority: "https://login.microsoftonline.com/common/",
redirectUri: "http://localhost:4200/",
validateAuthority : true,
popUp: true
}),
Authetification is working and I get the token.
Then when I'm in home page I make a second request to Microsoft Graph API to get user information using that token.
getProfile() {
let header= new Headers();
let tokenid= sessionStorage.getItem('msal.idtoken');
header.set('Authorization', 'Bearer ' + tokenid)
let url ="https://graph.microsoft.com/v1.0/me/"
return this.http.get(url,{headers:header});
}
}
I get an 401 Unauthorized error with a response :
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "xxxxxx",
"date": "2018-10-09T22:58:41"
}
}
}
I don't know why MG API is not accepting my token, Am I using wrong authority url ?
UPDATE: I have understood that actually I get id_token which is different from access token. How can I get Access token from MSAL library to make MS GRAPH API calls ?:
According to the same sample you can also attach an HttpInterceptor that will automatically attach the access token to each (external) HTTP call.
By reading through the documentation I found the following information.
consentScopes: Allows the client to express the desired scopes that should be consented. Scopes can be from multiple resources/endpoints. Passing scope here will only consent it and no access token will be acquired till the time client actually calls the API. This is optional if you are using MSAL for only login (Authentication).
That suggests that using the HttpInterceptor doesn't only attach the access token, but also retrieves it. The token that you're seeing is probably just a token for your application, but isn't a valid token for the Graph API.
Internally it uses getCachedTokenInternal(scopes: Array<string>, user: User) to get a new access token for specific scopes code found here. I'm not sure if you can use this method as well to get a new token for that resource. I would just use the interceptor.
You could try to copy the access token and see how it looks like on jwt.ms (a Microsoft provided JWT token viewer) or jwt.io.
Any tokens valid for Graph should have the Audience of https://graph.microsoft.com, so if you inspect the token (in jwt.ms) it should at least have this value.
"aud": "https://graph.microsoft.com",
The issue is that you're using the id_token instead of the access token:
let tokenid= sessionStorage.getItem('msal.idtoken');
becomes something like:
let tokenid= sessionStorage.getItem('msal.token'); // or msal.accesstoken
Update(per Phillipe's comment)
You need to select the scopes that you want to target in your application. So, it looks like you want the user profile, so you'll want to add the consentScopes property to specify which scopes your app will use:
MsalModule.forRoot({
clientID: "Tenant ID",
authority: "https://login.microsoftonline.com/common/",
redirectUri: "http://localhost:4200/",
validateAuthority : true,
popUp: true,
consentScopes: ["user.read"]
}),
Make sure you add your endpoint to Resource Map configuration. See this link: https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/MSALAngularDemoApp
export const protectedResourceMap:[string, string[]][]=[ ['https://graph.microsoft.com/v1.0/me', ['user.read']] ];

Google API bad input string

I am having an issue authenticating through the Google API system using the googleapis library. I have tried multiple other libraries as well without success.
The error I am getting can be seen below. It is
TypeError: Bad input string
I have a .json file that was created through the Google API Console, the service account has all permissions available as well as domain wide delegation. I have tried it without DwD as well which didn't work either.
The code I am using to authenticate is as follows:
let { google } = require('googleapis');
let privatekey = require('../config/keys/CCKey.json');
let jwtClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
['https://www.googleapis.com/auth/analytics']);
//authenticate request
jwtClient.authorize(function (err, tokens) {
if (err) {
console.log(err);
return;
} else {
console.log("Successfully connected!");
}
});
The JSON file that was generated by the Google API Console is as follows:
{
"type": "service_account",
"project_id": "xxx-1xx70xxxx4xx6",
"private_key_id": "xxxxxxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----\nxxxxx\n-----END PRIVATE KEY-----\n",
"client_email": "xxxx-service-account#xxxx-1xxx6.iam.gserviceaccount.com",
"client_id": "1xxxx2",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxxx"
}
I believe your problem might be to do with setting Managing API Client Access on your G Suite domain. This will need to be set by someone with Super Admin Access.
For some further information see the following link:
Perform G Suite Domain-Wide Delegation of Authority
And browse down to the section Delegate domain-wide authority to your service account
In your case, the Client Name would be your project_id from your service account JSON (xxx-1xx70xxxx4xx6) and you would need to set your scopes to https://www.googleapis.com/auth/analytics

Categories

Resources