问题
I have spreadsheets that need to be converted to PDF by various users in my organisation. In order to do that I am trying to use OAuth2 (https://github.com/googlesamples/apps-script-oauth2).
When I am using it in a main spreadsheet embedded script it works. However I am trying to move the OAuth2 code to a separate library as there will be many spreadsheets that will need the same functionality. When I am using this library I am getting the message "The state token is invalid or has expired. Please try again."
The library code:
var PROPERTY_KEY = "ExportPdfOauth2";
function initialStore() {
setAuthenticationPackage_( {
clientId : '10511......b43bu.apps.googleusercontent.com',
clientSecret : 'WYUsq...-h_',
projectKey : 'MxJ.......xOvW',
scopes : ['https://spreadsheets.google.com/feeds/']
});
}
function setAuthenticationPackage_(package) {
PropertiesService.getScriptProperties().setProperty(PROPERTY_KEY, JSON.stringify(package));
}
function getAuthenticationPackage_() {
var p = PropertiesService.getScriptProperties().getProperty(PROPERTY_KEY);
return p ? JSON.parse(p) : {};
}
function getExportPdfService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
var package = getAuthenticationPackage_();
return OAuth2.createService('exportPdf')
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId(package.clientId)
.setClientSecret(package.clientSecret)
// Set the project key of the script using this library.
.setProjectKey(package.projectKey)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
.setScope(package.scopes)
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}
function authCallback(request) {
var user = Session.getActiveUser().getEmail();
var exportPdfService = getExportPdfService();
var isAuthorized = exportPdfService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success');
} else {
return HtmlService.createHtmlOutput('Failure');
}
}
function getExportPdfRequest() {
var user = Session.getActiveUser().getEmail();
var exportPdfService = getExportPdfService();
if (!exportPdfService.hasAccess()) {
var template = HtmlService.createTemplate('Authorisation required in order to enable conversion to pdf. You will need to perform the operation again once the authorisation is complete.')+
'<br /><br />'+
'<a href="<?= authorizationUrl ?>" target="_blank">'+
'Authorise'+
'</a>');
template.authorizationUrl = exportPdfService.getAuthorizationUrl();
var page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
return null;
}
var request = {
headers: {
Authorization: 'Bearer ' + exportPdfService.getAccessToken()
}
};
return request;
}
The library is called by the embedded script as follows (please note that I put a callback function here that will call back the library):
function test(){
var id = 'ABCD.....'; // Spreadsheet to be converted to pdf
var name = 'test.pdf';
var domain = 'XXXXX';
var pdfContent = spreadsheetToPDF(id,domain,name);
if (pdfContent) DocsList.createFile(pdfContent);
}
// Convert spreadsheet to PDF file.
function spreadsheetToPDF(id,domain,name) {
SpreadsheetApp.flush();
var request = testPdfLib.getExportPdfRequest();
if (!request) return null;
//define the params URL to fetch
var params = '?fitw=true&exportFormat=pdf&format=pdf&size=A4&portrait=true&sheetnames=false&printtitle=false&gridlines=false&pagenum=CENTER';
var url = "https://docs.google.com/a/"+domain+"/spreadsheets/d/"+id+"/export"+params;
//fetching file url
var blob = UrlFetchApp.fetch(url, request);
blob = blob.getBlob().setName(name);
//return file
return blob;
}
function authCallback(request) {
testPdfLib.authCallback(request);
}
I have also looked at another post at How to correctly construct state tokens for callback urls in Managed Libraries? but still can not figure out what I am doing wrong as I have provided the callback function at the main calling script. At the developers console my REDIRECT URIS points to the library. I tried to point it to the main script but I get the same results (though I wouldn't like to do so as the script will be copied by many users and it will be impossible to create a new client Id for each instance of the calling script).
Appreciate any help!
来源:https://stackoverflow.com/questions/29267570/oauth2-support-through-library-returns-the-state-token-is-invalid-or-has-expired