I had written a Google Apps Script that connected to Google Cloud Print to automate some printing. The script would auto-run on a time interval, search for relevant files, and if found it would sent them to my printer. My code used OAuthConfig and was working fine, but now that class has been deprecated and after a weekend of trial & error and scouring the interwebs I can't get it to work with OAuth2.
Here's the OAuthConfig code that was working fine:
function printDoc(docId, docTitle, myPrinterId) {
var scope = 'https://www.googleapis.com/auth/cloudprint';
var url = 'https://www.google.com/cloudprint/submit';
var payloadOfSubmit = {
"printerid" : myPrinterId,
"title" : docTitle,
"content" : docId,
"contentType" : "google.kix"
};
var fetchArgs = googleOAuth_('google', scope, payloadOfSubmit);
fetchArgs.method = 'POST';
var responseOfSubmit = UrlFetchApp.fetch(url, fetchArgs);
var jsonOfSubmit = JSON.parse(responseOfSubmit.getContentText());
return jsonOfSubmit;
}
function googleOAuth_(name, scope, payloadData) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey("anonymous");
oAuthConfig.setConsumerSecret("anonymous");
return {
oAuthServiceName:name,
oAuthUseToken:"always",
muteHttpExceptions:true,
payload:payloadData
};
}
I've successfully connected the github library for OAuth2. However, what's different about the instructions provided there, and on many other sites, is that they assume that the code will be deployed as a web service where a user is prompted to manually click to authorize the request. In my case the code will be saved on a Google Apps Script file, and the Cloud Printer is on the same Google account, so I never needed this manual intervention or back & forth with my original OAuthconfig.
My first attempt by adapting the instructions was:
function printDoc2(docId, docTitle, myPrinterId) {
var url = 'https://www.google.com/cloudprint/submit';
var scope = 'https://www.googleapis.com/auth/cloudprint';
var payloadOfSubmit = {
"printerid" : myPrinterId,
"title" : docTitle,
"content" : docId,
"contentType" : "google.kix",
};
var accessToken = googleOAuth_('google', scope).getAccessToken();
var params = {
method:"POST",
headers: {"Authorization": "Bearer " + accessToken},
muteHttpExceptions:true,
payload:payloadOfSubmit
};
var responseOfSubmit = UrlFetchApp.fetch(url, params);
//Logger.log(responseOfSubmit);
var jsonOfSubmit = JSON.parse(responseOfSubmit.getContentText());
return jsonOfSubmit;
}
function googleOAuth2_(name, scope) {
return OAuth2.createService(name)
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId("anonymous")
.setClientSecret("anonymous")
.setProjectKey(ScriptApp.getProjectKey())
.setPropertyStore(PropertiesService.getUserProperties())
.setScope(scope)
.setCallbackFunction('authCallback');
}
function authCallback(request) {
var driveService = getDriveService();
var isAuthorized = driveService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
But this gives me an error "Access not granted or expired" when it tries to run the line:
var accessToken = googleOAuth_('google', scope).getAccessToken();
So I found a apps ScriptApp Method getOAuthToken which seemed like it might give me the token I need. I replaced the above line with:
var accessToken = ScriptApp.getOAuthToken();
And the code executes but my response from the server is "Error 403 User credentials required".
Here's my third attempt based on @Mogsdad's suggestion:
function sendPrintJob(docId,myPrinterId,docTitle) {
var payloadOfSubmit = {
"printerid" : myPrinterId,
"title" : docTitle,
"content" : docId,
"contentType" : "google.kix" ,
};
var request = {
"method": "POST",
"headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
var responseOfSubmit = UrlFetchApp.fetch("https://www.google.com/cloudprint/submit", request);
Logger.log(responseOfSubmit);
}
I've tried a number of variations, including creating a Developer Console Project and using the Client ID provided there, but I keep getting stuck at these two issues (access not granted, or credentials required). If anyone can provide any help I'd really appreciate it.
Here are the steps that allowed me to connect Google Apps Script to Google Cloud Print, so I could then submit GCP jobs (these steps are all started from within Google Apps Script):
MswhXl8fVhTFUH_Q3UOJbXvxhMjh3Sh48
> Selecthttps://script.google.com/macros/d/{PROJECT KEY}/usercallback
where project key is under File > Project Properties and copy
your client ID and client secretclient_id
and client_secret
)Printer ID
(it will be of the format 555aa555-5a55-5555-5555-55555a55a555
)myPrinterId
)This resource was helpful in figuring the steps out: http://ctrlq.org/code/20061-google-cloud-print-with-apps-script, and you may also find these links helpful:
function showURL() {
var cpService = getCloudPrintService();
if (!cpService.hasAccess()) {
Logger.log(cpService.getAuthorizationUrl());
} else {
Logger.log("You already have access to this service.");
}
}
function getCloudPrintService() {
return OAuth2.createService('print')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId(client_id)
.setClientSecret(client_secret)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('https://www.googleapis.com/auth/cloudprint')
.setParam('login_hint', Session.getActiveUser().getEmail())
.setParam('access_type', 'offline')
.setParam('approval_prompt', 'force');
}
function authCallback(request) {
var isAuthorized = getCloudPrintService().handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('You can now use Google Cloud Print from Apps Script.');
} else {
return HtmlService.createHtmlOutput('Cloud Print Error: Access Denied');
}
}
function getPrinterList() {
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/search', {
headers: {
Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
},
muteHttpExceptions: true
}).getContentText();
var printers = JSON.parse(response).printers;
for (var p in printers) {
Logger.log("%s %s %s", printers[p].id, printers[p].name, printers[p].description);
}
}
function printGoogleDocument(docId, docTitle) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid" : myPrinterId,
"content" : docId,
"title" : docTitle,
"contentType" : "google.kix", // allows you to print google docs
"ticket" : JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}