OfficeDev / office-js

A repo and NPM package for Office.js, corresponding to a copy of what gets published to the official "evergreen" Office.js CDN, at https://appsforoffice.microsoft.com/lib/1/hosted/office.js.
https://learn.microsoft.com/javascript/api/overview
Other
670 stars 96 forks source link

Excel Custom Function - Shared Javascript Runtime - CORS error #2178

Closed jgauntz closed 5 months ago

jgauntz commented 2 years ago

Message from office-js bot: We’re closing this issue because it has been inactive for a long time. We’re doing this to keep the issues list manageable and useful for everyone. If this issue is still relevant for you, please create a new issue. Thank you for your understanding and continued feedback.

I am having a terrible time getting my excel custom function to call an API with basic authentication in the header. I get a CORs error. To the best of my knowledge, I have configured my function to use the Javascript Shared Runtime as I am able to set and retrieve values from global memory (window.sharedState). Below is the code from my custom function - I have removed the key used for basic authentication. Any help is greatly appricated. I have also attached my manifest.xml file and my webpack.config.js file.

manifest.xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

91b99970-deb4-48d2-94f9-aa2c6acc630f 1.0.0.0 Contoso en-US https://www.contoso.com ReadWriteDocument <Description resid="GetStarted.Description"/> <LearnMoreUrl resid="GetStarted.LearnMoreUrl"/> </GetStarted> <FunctionFile resid="Taskpane.Url"/> <ExtensionPoint xsi:type="PrimaryCommandSurface"> <OfficeTab id="TabHome"> <Group id="CommandsGroup"> <Label resid="CommandsGroup.Label"/> <Icon> <bt:Image size="16" resid="Icon.16x16"/> <bt:Image size="32" resid="Icon.32x32"/> <bt:Image size="80" resid="Icon.80x80"/> </Icon> <Control xsi:type="Button" id="TaskpaneButton"> <Label resid="TaskpaneButton.Label"/> <Supertip> <Title resid="TaskpaneButton.Label"/> <Description resid="TaskpaneButton.Tooltip"/> </Supertip> <Icon> <bt:Image size="16" resid="Icon.16x16"/> <bt:Image size="32" resid="Icon.32x32"/> <bt:Image size="80" resid="Icon.80x80"/> </Icon> <Action xsi:type="ShowTaskpane"> <TaskpaneId>ButtonId1</TaskpaneId> <SourceLocation resid="Taskpane.Url"/> </Action> </Control> </Group> </OfficeTab> </ExtensionPoint> </DesktopFormFactor> </Host> </Hosts> <Resources> <bt:Images> <bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/> <bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/> <bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/> </bt:Images> <bt:Urls> <bt:Url id="Functions.Script.Url" DefaultValue="https://localhost:3000/dist/functions.js"/> <bt:Url id="Functions.Metadata.Url" DefaultValue="https://localhost:3000/dist/functions.json"/> <bt:Url id="Functions.Page.Url" DefaultValue="https://localhost:3000/dist/functions.html"/> <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/> <bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/> <bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/> </bt:Urls> <bt:ShortStrings> <bt:String id="Functions.Namespace" DefaultValue="CONTOSO"/> <bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!"/> <bt:String id="CommandsGroup.Label" DefaultValue="Commands Group"/> <bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/> </bt:ShortStrings> <bt:LongStrings> <bt:String id="GetStarted.Description" DefaultValue="Your sample add-in loaded succesfully. Go to the HOME tab and click the 'Show Taskpane' button to get started."/> <bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to Show a Taskpane"/> </bt:LongStrings> </Resources> </VersionOverrides> </OfficeApp> <p>webpack.config.js /<em> eslint-disable no-undef </em>/</p> <p>const devCerts = require("office-addin-dev-certs"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const CustomFunctionsMetadataPlugin = require("custom-functions-metadata-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin");</p> <p>const urlDev = "<a rel="noreferrer nofollow" target="_blank" href="https://localhost:3000/">https://localhost:3000/</a>"; const urlProd = "<a rel="noreferrer nofollow" target="_blank" href="https://www.contoso.com/">https://www.contoso.com/</a>"; // CHANGE THIS TO YOUR PRODUCTION DEPLOYMENT LOCATION</p> <p>/<em> global require, module, process, __dirname </em>/</p> <p>async function getHttpsOptions() { const httpsOptions = await devCerts.getHttpsServerOptions(); return { cacert: httpsOptions.ca, key: httpsOptions.key, cert: httpsOptions.cert }; }</p> <p>module.exports = async (env, options) => { const dev = options.mode === "development"; const buildType = dev ? "dev" : "prod"; const config = { devtool: "source-map", entry: { polyfill: ["core-js/stable", "regenerator-runtime/runtime"], functions: "./src/functions/functions.js", taskpane: "./src/taskpane/taskpane.js", commands: "./src/commands/commands.js", }, output: { devtoolModuleFilenameTemplate: "webpack:///[resource-path]?[loaders]", clean: true, }, resolve: { extensions: [".ts", ".tsx", ".html", ".js"], }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, { test: /.html$/, exclude: /node_modules/, use: "html-loader", }, { test: /.(png|jpg|jpeg|gif|ico)$/, type: "asset/resource", generator: { filename: "assets/[name][ext][query]", }, }, ], }, plugins: [ new CustomFunctionsMetadataPlugin({ output: "functions.json", input: "./src/functions/functions.js", }),</p> <pre><code> new HtmlWebpackPlugin({ filename: "taskpane.html", template: "./src/taskpane/taskpane.html", chunks: ["polyfill", "taskpane", "commands", "functions"], }), new CopyWebpackPlugin({ patterns: [ { from: "manifest*.xml", to: "[name]." + buildType + "[ext]", transform(content) { if (dev) { return content; } else { return content.toString().replace(new RegExp(urlDev, "g"), urlProd); } }, }, ], }), ], devServer: { static: [__dirname], headers: { "Access-Control-Allow-Origin": "*", }, https: env.WEBPACK_BUILD || options.https !== undefined ? options.https : await getHttpsOptions(), port: process.env.npm_package_config_dev_server_port || 3000, },</code></pre> <p>};</p> <p>return config; };</p> <p>My custom function</p> <p>let url = "<a rel="noreferrer nofollow" target="_blank" href="https://servicechannel.atlassian.net/rest/api/2/project">https://servicechannel.atlassian.net/rest/api/2/project</a>"; var options = { method: 'GET', headers: { 'Host': 'servicechannel.atlassian.net', 'Authorization': 'Basic <my key>' } };</p> <p>return new Promise(function (resolve, reject) { fetch(url, options) .then(function (response){ window.sharedState = JSON.stringify(response.json()); } ) })</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/madhavagrawal17"><img src="https://avatars.githubusercontent.com/u/48529581?v=4" />madhavagrawal17</a> commented <strong> 2 years ago</strong> </div> <div class="markdown-body"> <p>@jgauntz, I want to give you some background on how Custom Functions with SharedRuntime will be working. If you have properly enabled SharedRuntime for Custom Functions (I don't see the details of the manifest.xml) then Custom Function will be running in a Browser WebView. So, the authentication code would be the same as you do for Browser. Also, I am not able to understand the current problem. Can you please describe the problem you are facing in detail? Can you paste the CORS error you are getting currently? </p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/adammpolak"><img src="https://avatars.githubusercontent.com/u/12940507?v=4" />adammpolak</a> commented <strong> 1 year ago</strong> </div> <div class="markdown-body"> <p>@jeremy-msft @chiz-ms @madhavagrawal17 I have the same issue</p> <p>Making an API call with Auth headers does not work with custom functions.</p> <p>Can you give an example of a POST call with an authorization header that works?</p> </div> </div> <div class="page-bar-simple"> </div> <div class="footer"> <ul class="body"> <li>© <script> document.write(new Date().getFullYear()) </script> Githubissues.</li> <li>Githubissues is a development platform for aggregating issues.</li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script> <script src="/githubissues/assets/js.js"></script> <script src="/githubissues/assets/markdown.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/highlight.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/languages/go.min.js"></script> <script> hljs.highlightAll(); </script> </body> </html>