I am new to Forge and using node.js - I am having some difficulty getting a simple 3-legged Oauth process to work.
This is how far I have got below. It gives me the error "Cannot GET /api/forge/oauth/callback"
I have checked that my callback url matches what is in the Forge App.
Ultimately what I am trying to achieve is, getting the shared link for a newly created file in Fusion teams, or at least opening the browser to the file overview page.
Would anybody be able to help with this?
var express = require('express');
var ForgeSDK = require('forge-apis');
const { stringify } = require('node:querystring');
var opn = require('opn');
// Set up Express web server
var app = express();
// Set the Forge Variables
var FORGE_CLIENT_ID = 'client-id', FORGE_CLIENT_SECRET = 'client-secret', REDIRECT_URL = 'http://localhost:3000/api/forge/oauth/callback';
// This is for web server to start listening to port 3000
app.set('port', 3000);
var server = app.listen(app.get('port'), function () {
console.log('Server listening on port ' + server.address().port);
});
// Initialize the 3-legged OAuth2 client, set specific scopes and optionally set the `autoRefresh` parameter to true
// if you want the token to auto refresh
var autoRefresh = true;
var oAuth2ThreeLegged = new ForgeSDK.AuthClientThreeLegged(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET, REDIRECT_URL, [
'data:read',
'data:write'
], autoRefresh);
// Generate a URL page that asks for permissions for the specified scopes.
var AuthURL = oAuth2ThreeLegged.generateAuthUrl();
console.log(AuthURL)
opn('https://developer.api.autodesk.com/authentication/v1/authorize?response_type=code&client_id=<<client-id>>&redirect_uri=http://localhost:3000/api/forge/oauth/callback&scope=data:read+data:write&state=undefined', {app: 'chrome'})
where is the callback API in your code?
BTW 3-Legged oauth is implemented here in nodejs, you can use it as reference:
https://learnforge.autodesk.io/#/oauth/3legged/nodejs
Related
Apologies if this is a silly question, I am very new to programming in general and I have never worked with OAuth before.
I am currently trying to build a Google App Script which interacts with an external service and authenticates using OAuth2.
I am having a lot of trouble with OAuth2... for starters, I'm not sure I am using the correct library for this. I am going off the one recommended by Google for ads script - https://developers.google.com/google-ads/scripts/docs/examples/oauth20-library
I know there is another popular one available in GitHub https://github.com/googleworkspace/apps-script-oauth2
I was not able to use it because everything comes out as 'is not a function', no matter how I add the library, manually or through the built-in feature.
I started building the API call, based on the first library and I had some partial success, I started getting back a 500 error message and I realized my accessToken is null.
function SHICall(){
var tokenUrl = "X/token";
const scriptProperties = PropertiesService.getScriptProperties();
var clientId = scriptProperties.getProperty('CLIENT_ID');
var clientSecret = scriptProperties.getProperty('SECRET');
var opt_scope = "CustomerAPI.Public";
// Access token is obtained and cached.
const authUrlFetch = OAuth2.withClientCredentials(tokenUrl, clientId, clientSecret, opt_scope);
const url = "X";
Logger.log(authUrlFetch);
var options = {
headers: { 'Content-Type': "application/json", 'Accept': "application/json"},
muteHttpExceptions: true,
method: "GET",
contentType: "application/json",
validateHttpsCertificates: false,
};
// Use access token in each request
const response = authUrlFetch.fetch(url, options);
// ... use response
Logger.log(response);
}
Any clue why the token is coming back as null? I based my API Call on google's documentation again https://developers.google.com/google-ads/scripts/docs/features/third-party-apis#oauth_2
I'm trying to allow google sheets to interact with the Podio api. The first step is Oauth2 auth and I'm trying to follow https://developers.podio.com/authentication/app_auth on which I have the following initial code:
function podio1() {
const CLIENTID = '????'
const CLIENTSECRET = 'lP???'
const APPID = '????'
const APPTOKEN = '????'
const MYURL = 'script.google.com/macros/d/?????n_5ULh_JGhMwZNapyVDcp7-oMle9/usercallback'
var options =
{
"method" : "post"
};
var result = UrlFetchApp.fetch("https://podio.com/oauth/token?grant_type=app&app_id=APPID&app_token=APPTOKEN&client_id=CLIENTID&redirect_uri=MYURL&client_secret=CLIENTSECRET",options);
Logger.log(result.getContentText());
var json = result.getContentText();
var data = JSON.parse(json);
}
I was able to get the first 4 parameters from https://podio.com/settings/api and the specific apps developer tab respectively.
I tried to set the redirect url in the box titled: 'Full domain (without protocol) of your return URL (e.g. mypodioapp.com)' (see screenshot)
I'm getting the following error:
script.google.com/macros/d/1??????????yVDcp7-oMle9/usercallback is not a valid domain
How do I set the redirect url?
"Full domain (without protocol) of your return URL (e.g. mypodioapp.com)" is looking for only the domain - not the whole redirect link.
In your case, it would simply be script.google.com
I am using the v3 .Net Google Apis. This seems like it should be a simple task, but nothing I have tried seems to work.
I am able to get the file resource for the file I want by doing this -
var fileRequest = service.Files.Get(fileId);
fileRequest.Fields = "*";
var fileResponse = fileRequest.Execute();
But then I have not been able to actually find a way to download the file. If I use this -
var exportRequest = service.Files.Export(fileResponse.Id, fileResponse.MimeType);
exportRequest.Download(stream);
It returns a 403 Forbidden status with a message stating that Export is only for Google docs.
I've tried this -
var downloadTask = exportRequest.MediaDownloader.DownloadAsync(#"https://docs.google.com/uc?export=download&id=" + fileResponse.Id, file);
downloadTask.Wait();
But that just returns the markup for the page for the user to login. I created the export request using a service account so login should not be required.
Any have a sample of doing this in .Net using the V3 google API?
Ok, I literally got this to work 5 minutes after posting this. Here is what I found works (I know I tried this before and it did not work, but who knows) -
public static async Task DownloadFile(string fileId, DriveService service)
{
var fileRequest = service.Files.Get(fileId);
fileRequest.Fields = "*";
var fileResponse = fileRequest.Execute();
var exportRequest = service.Files.Get(fileResponse.Id);
//you would need to know the file size
var size = fileResponse.Size;
var file = new FileStream(fileResponse.Name, FileMode.OpenOrCreate, FileAccess.ReadWrite);
file.SetLength((long)size);
var response = await fileRequest.DownloadAsync(file);
if (response.Status == Google.Apis.Download.DownloadStatus.Failed)
{
Console.WriteLine("Download failed");
}
}
I've deployed a protected web app, and I'd like to trigger it without logging in each time:
I'd like to access the web app URL without logging in:
Based on this document, it's not possible without logging in from browser:
https://github.com/tanaikech/taking-advantage-of-Web-Apps-with-google-apps-script/blob/master/README.md
If the script of Web Apps uses some scopes, client users have to
authorize the scopes by own browser.
I'm assuming scopes means the web app is protected.
I've tried this: https://github.com/gsuitedevs/apps-script-oauth2/blob/master/samples/GoogleServiceAccount.gs but it asks for "request access"
If I click on request access, then it shows me this:
At this point, I'm thinking it's not possible to setup a service account with scope to trigger a protected deployed web app without authenticating through a browser each time. Can anyone confirm this?
My assumption is that the web app scope is https://www.googleapis.com/auth/drive since it has access to all drive's files.
Update: (What I tried but didn't work)
I matched the scope from the script:
To the service account:
The blurred area above is the client id i got from:
I've generated the access token using this script:
function accessTokens(){
var private_key = "-----BEGIN PRIVATE KEY-----*****\n-----END PRIVATE KEY-----\n"; // private_key of JSON file retrieved by creating Service Account
var client_email = "****#****.iam.gserviceaccount.com"; // client_email of JSON file retrieved by creating Service Account
var scopes = ["https://www.googleapis.com/auth/documents","https://www.googleapis.com/auth/forms","https://www.googleapis.com/auth/script.external_request","https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"]; // Scopes
var url = "https://www.googleapis.com/oauth2/v3/token";
var header = {
alg: "RS256",
typ: "JWT",
};
var now = Math.floor(Date.now() / 1000);
var claim = {
iss: client_email,
scope: scopes.join(" "),
aud: url,
exp: (now + 3600).toString(),
iat: now.toString(),
};
var signature = Utilities.base64Encode(JSON.stringify(header)) + "." + Utilities.base64Encode(JSON.stringify(claim));
var jwt = signature + "." + Utilities.base64Encode(Utilities.computeRsaSha256Signature(signature, private_key));
var params = {
method: "post",
payload: {
assertion: jwt,
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
},
};
var res = UrlFetchApp.fetch(url, params).getContentText();
Logger.log(res);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
sheet.getRange(1, 3).setValue(JSON.parse(res)['access_token']);
}
And still has the same error, it asks for request access.
After a couple days into this, I've figured it out (with help of course).
Get the scope from your deployed web app script: File > Project Properties > Scopes
Add the scope along with https://www.googleapis.com/auth/drive in page Manage API client access https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients (use comma delimited to add multiple scopes: http...,http..., etc.)
For the client name, get the client id from the service account page in your admin console: https://console.developers.google.com
Deploy your script Publish > Deploy as Web App
After generating access token(instruction below), append the access token with your deployed web app url &access_token=YOURTOKENHERE
Use this script with a google sheet, it will generate the access_token in cell A1 of Sheet1 (Replace the 4 variables with the info relevant to you):
function accessTokens(){
var private_key = "-----BEGIN PRIVATE KEY-----n-----END PRIVATE KEY-----\n"; // private_key of JSON file retrieved by creating Service Account
var client_email = "*****#****.iam.gserviceaccount.com"; // client_email of JSON file retrieved by creating Service Account
var scopes = ["https://www.googleapis.com/auth/documents","https://www.googleapis.com/auth/forms","https://www.googleapis.com/auth/script.external_request","https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/drive"]; // Scopes
var impersonate_email = "" //impersonate email
var url = "https://www.googleapis.com/oauth2/v4/token";
var header = {
alg: "RS256",
typ: "JWT",
};
var now = Math.floor(Date.now() / 1000);
var claim = {
iss: client_email,
sub: impersonate_email,
scope: scopes.join(" "),
aud: url,
exp: (now + 3600).toString(),
iat: now.toString(),
};
var signature = Utilities.base64Encode(JSON.stringify(header)) + "." + Utilities.base64Encode(JSON.stringify(claim));
var jwt = signature + "." + Utilities.base64Encode(Utilities.computeRsaSha256Signature(signature, private_key));
var params = {
method: "post",
payload: {
assertion: jwt,
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
},
};
var res = UrlFetchApp.fetch(url, params).getContentText();
Logger.log(res);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
sheet.getRange(1, 1).setValue(JSON.parse(res)['access_token']);
}
I'm trying to setup a simple login API using node.js/restify. The code below shows a simple route, with nothing but a console.log() statement within it, as I'm just trying to prove I can gain a connection.
var restify = require('restify');
var user = require('./user');
var reference = require('./reference');
var fs = require('fs');
var bodyParser = require('body-parser');
var _= require('lodash');
const server = restify.createServer();
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({extended:false}));
server.use(restify.plugins.fullResponse())
server.use(restify.plugins.bodyParser());
server.use(restify.plugins.queryParser()) server.use(restify.plugins.authorizationParser())
var port = 8080;
server.post('/user/login', (req, res) => {
console.log("---LOGIN ATTEMPT---");
res.status(200);
res.end();
});
Using Postman for testing, I expect to get a statement back in the console, stating "LOGIN ATTEMPT".
Postman freezes with the 'Loading' text and stays like that until it crashes saying 'There was an error connecting to localhost:8080/user/login'. This only occurs when sending JSON data and not when sending form-data, which is where my confusion is occurring. It is acting as if an infinite loop is occurring with JSON data but can not trace where it is happening.
because you are not sending any data back to requesting browser(in this case postman) try returning some response as body
for example use res.send('success')