You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用apps-script-oauth2库时handleCallback函数报code未定义错误

问题描述

调用authCallback函数时遇到以下错误:

TypeError: Cannot read properties of undefined (reading 'code')
at Service_.handleCallback(Service:440:40)
at authCallback(Auth:69:39)

日志显示请求中存在code参数,但报错提示无法读取该参数。相关代码如下(错误发生在handleCallback调用处):

function doGet(e) {
 return initiateAuthorization(); // Or any other function you want to run when the web app is accessed directly
}

function getAdobeSignService_() {
  // 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.
  return OAuth2.createService('adobeSign')

      // Set the endpoint URLs
      .setAuthorizationBaseUrl('https://secure.na4.adobesign.com/public/oauth/v2')
      .setTokenUrl('https://secure.na4.adobesign.com/public/oauth/v2/token')

      // Set the client ID and secret
      .setClientId('..')
      .setClientSecret('..')

      // 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
      .setScope('agreement_send')
      
      // Requests offline access.
      .setParam('access_type', 'offline')

      // Consent prompt is required to ensure a refresh token is always
      // returned when requesting offline access.
      .setParam('prompt', 'consent');
}

function initiateAuthorization() {
 var adobeSignService = getAdobeSignService_();
 console.log("done getting adobe sign service");
 var userProperties = PropertiesService.getUserProperties();

  if (!adobeSignService.hasAccess()) {
    var authorizationUrl = adobeSignService.getAuthorizationUrl();
    var template = HtmlService.createTemplate(
      '<a href="<?= authorizationUrl?>" target="_blank">Authorize</a>. ' +
      'Reopen the sidebar when the authorization is complete.');
    template.authorizationUrl = authorizationUrl;
    var page = template.evaluate();
    return page; // Return the HTML output directly. No SpreadsheetApp.getUi() here.

  } else {
    var justAuthorized = userProperties.getProperty('adobeSignAuthorized');
    if (justAuthorized === 'true') {
      userProperties.deleteProperty('adobeSignAuthorized');
    }

    getAgreements(function(agreements){
        updateSheetWithAgreements(agreements);
    });

    return HtmlService.createHtmlOutput("Authorization Complete. Data will be updated.");
  }
}


function authCallback(request) {
  var adobeSignService = getAdobeSignService_();
  var jsonRequest = JSON.stringify(request) 
  var isAuthorized = adobeSignService.handleCallback(jsonRequest);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}


function getAgreements() {  // Example: Function to get agreements
  var adobeSignService = getAdobeSignService();
  var accessToken = adobeSignService.getAccessToken();

  // Construct the Adobe Sign API request URL (Example)
  var apiUrl = 'https://api.na1.echosign.com/api/rest/v6/agreements';

  try {
    var response = UrlFetchApp.fetch(apiUrl, {
      method: 'get', // Or post, put, delete as needed
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Accept': 'application/json' // Important: specify JSON
      },
      muteHttpExceptions: true // Handle potential errors gracefully
    });

    var data = JSON.parse(response.getContentText());
    Logger.log(data); // Log the response data (for debugging)

    // Process the data as needed (e.g., display in spreadsheet)
    // Example: Loop through the agreements and log their IDs
    if (data && data.hasOwnProperty("agreementList")) {
      data.agreementList.forEach(function(agreement) {
        Logger.log("Agreement ID: " + agreement.agreementId);
      });
    } else {
      Logger.log("No agreements found or unexpected response format.");
      Logger.log(response); // Log the full response for debugging
    }


  } catch (error) {
    Logger.log("Error making API request: " + error);
    Logger.log(response); // Log the full response for debugging
    // Handle the error (e.g., display an error message in the sidebar)
  }
}

打印的jsonRequest值如下:

{parameter={redir=, code=**value**, state=**value**, serviceName=adobeSign, authuser=0}, contextPath=, parameters={authuser=[0], serviceName=adobeSign, code=[**value**], state=[**value**], redir=[]}, contentLength=-1.0, queryString=code=**value**&state=**value**&authuser=0&redir}

请问jsonRequest的值是否存在问题?


解决方案

问题出在authCallback函数的参数传递上:你把request对象转成了JSON字符串传给handleCallback,但OAuth2库的handleCallback方法需要接收原始的request对象,而非字符串化后的JSON。

当传入字符串时,库内部尝试读取jsonRequest.code,但字符串本身没有code属性,因此抛出"Cannot read properties of undefined (reading 'code')"的错误。你的jsonRequest内容本身是正常的,包含了code参数,只是传递方式错误导致库无法正确解析。

修改后的authCallback函数如下:

function authCallback(request) {
  var adobeSignService = getAdobeSignService_();
  // 移除JSON.stringify,直接传递原始request对象
  var isAuthorized = adobeSignService.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}

内容的提问来源于stack exchange,提问作者Katrina Trial

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 08:47:39