|
1 | 1 | --- |
2 | 2 | title: Authentication for custom functions without a shared runtime |
3 | | -description: Authenticate users using custom functions that don't use a shared runtime. |
4 | | -ms.date: 02/10/2024 |
| 3 | +description: Learn how to authenticate users in Excel custom functions that run in a JavaScript-only runtime and share tokens with a task pane. |
| 4 | +ms.date: 06/17/2026 |
5 | 5 | ms.topic: how-to |
6 | 6 | ms.localizationpriority: medium |
7 | 7 | --- |
8 | 8 |
|
9 | 9 | # Authentication for custom functions without a shared runtime |
10 | 10 |
|
11 | | -In some scenarios, a custom function that doesn't use a [shared runtime](../testing/runtimes.md#shared-runtime) will need to authenticate the user in order to access protected resources. Custom functions that don't use a shared runtime run in a [JavaScript-only runtime](../testing/runtimes.md#javascript-only-runtime). Because of this, if the add-in has a task pane, you'll need to pass data back and forth between the JavaScript-only runtime and the HTML-supporting runtime used by the task pane. You do this by using the [OfficeRuntime.storage](/javascript/api/office-runtime/officeruntime.storage) object and a special Dialog API. |
| 11 | +If your Excel custom function doesn't use a [shared runtime](../testing/runtimes.md#shared-runtime), it runs in a [JavaScript-only runtime](../testing/runtimes.md#javascript-only-runtime). In that runtime, authentication usually requires a dialog flow and token sharing with your task pane. |
12 | 12 |
|
13 | | -[!include[Shared runtime note](../includes/shared-runtime-note.md)] |
| 13 | +Use [OfficeRuntime.displayWebDialog](/javascript/api/office-runtime#office-runtime-officeruntime-displaywebdialog-function(1)) to sign in and [OfficeRuntime.storage](/javascript/api/office-runtime/officeruntime.storage) to cache and share the token between runtimes. |
14 | 14 |
|
15 | | -## OfficeRuntime.storage object |
16 | | - |
17 | | -The JavaScript-only runtime doesn't have a `localStorage` object available on the global window, where you typically store data. Instead, your code should share data between custom functions and task panes by using `OfficeRuntime.storage` to set and get data. |
18 | | - |
19 | | -### Suggested usage |
20 | | - |
21 | | -When you need to authenticate from a custom function add-in that doesn't use a shared runtime, your code should check `OfficeRuntime.storage` to see if the access token was already acquired. If not, use [OfficeRuntime.displayWebDialog](/javascript/api/office-runtime#office-runtime-officeruntime-displaywebdialog-function(1)) to authenticate the user, retrieve the access token, and then store the token in `OfficeRuntime.storage` for future use. |
| 15 | +[!INCLUDE [Shared runtime note](../includes/shared-runtime-note.md)] |
22 | 16 |
|
23 | | -## Dialog API |
24 | | - |
25 | | -If a token doesn't exist, you should use the `OfficeRuntime.dialog` API to ask the user to sign in. After a user enters their credentials, the resulting access token can be stored as an item in `OfficeRuntime.storage`. |
| 17 | +## Authentication workflow |
26 | 18 |
|
27 | | -> [!NOTE] |
28 | | -> The JavaScript-only runtime uses a dialog object that is slightly different from the dialog object in the browser runtime used by task panes. They're both referred to as the "Dialog API", but use [OfficeRuntime.displayWebDialog](/javascript/api/office-runtime#office-runtime-officeruntime-displaywebdialog-function(1)) to authenticate users in the JavaScript-only runtime, *not* [Office.ui.displayDialogAsync](/javascript/api/office/office.ui#office-office-ui-displaydialogasync-member(1)). |
| 19 | +The following workflow is typical for custom functions that don't use a shared runtime. |
29 | 20 |
|
30 | | -The following diagram outlines this basic process. The dotted line indicates that custom functions and your add-in's task pane are both part of your add-in as a whole, though they use separate runtimes. |
31 | | - |
32 | | -1. You issue a custom function call from a cell in an Excel workbook. |
33 | | -1. The custom function uses `OfficeRuntime.dialog` to pass your user credentials to a website. |
34 | | -1. This website then returns an access token to the page in the dialog. |
35 | | -1. Your JavaScript in the dialog calls the [Office.ui.messageParent](/javascript/api/office/office.ui#office-office-ui-messageparent-member(1)) function to send the access token to the custom function. For more information about this function, see [Send information from the dialog box to the host page](../develop/dialog-api-in-office-add-ins.md#send-information-from-the-dialog-box-to-the-host-page). |
36 | | -1. Your custom function then sets this access token to an item in the `OfficeRuntime.storage`. |
37 | | -1. Your add-in's task pane accesses the token from `OfficeRuntime.storage`. |
| 21 | +1. A user runs a custom function in an Excel cell. |
| 22 | +1. The custom function calls `OfficeRuntime.displayWebDialog` to open a sign-in page in a dialog, where the user enters their credentials. |
| 23 | +1. The sign-in page then returns an access token to the dialog. |
| 24 | +1. The dialog calls the [Office.ui.messageParent](/javascript/api/office/office.ui#office-office-ui-messageparent-member(1)) function to send the access token to the custom function. For more information about this function, see [Send information from the dialog box to the host page](../develop/dialog-api-in-office-add-ins.md#send-information-from-the-dialog-box-to-the-host-page). |
| 25 | +1. The custom function then sets this access token to an item in the `OfficeRuntime.storage`. |
| 26 | +1. The add-in's task pane accesses the token from `OfficeRuntime.storage`. |
38 | 27 |
|
39 | 28 | :::image type="content" source="../images/authentication-diagram.png" alt-text="Diagram of custom function using dialog API to get access token, and then share token with task pane through the OfficeRuntime.storage API."::: |
40 | 29 |
|
41 | | -## Storing the token |
42 | | - |
43 | | -The following examples are from the [Using OfficeRuntime.storage in custom functions](https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Excel-custom-functions/AsyncStorage) code sample. Refer to this code sample for a complete example of sharing data between custom functions and the task pane in add-ins that don't use a shared runtime. |
| 30 | +## Try it with a sample |
44 | 31 |
|
45 | | -If the custom function authenticates, then it receives the access token and will need to store it in `OfficeRuntime.storage`. The following code sample shows how to call the `storage.setItem` method to store a value. The `storeValue` function is a custom function that stores a value from the user. You can modify this to store any token value you need. |
| 32 | +Use the [Using OfficeRuntime.storage in custom functions](https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Excel-custom-functions/AsyncStorage) sample to test token storage and retrieval between custom functions and a task pane. |
46 | 33 |
|
47 | | -```js |
48 | | -/** |
49 | | - * Stores a key-value pair into OfficeRuntime.storage. |
50 | | - * @customfunction |
51 | | - * @param {string} key Key of item to put into storage. |
52 | | - * @param {*} value Value of item to put into storage. |
53 | | - */ |
54 | | -function storeValue(key, value) { |
55 | | - return OfficeRuntime.storage.setItem(key, value).then(function (result) { |
56 | | - return "Success: Item with key '" + key + "' saved to storage."; |
57 | | - }, function (error) { |
58 | | - return "Error: Unable to save item with key '" + key + "' to storage. " + error; |
59 | | - }); |
60 | | -} |
61 | | -``` |
62 | | - |
63 | | -When the task pane needs the access token, it can retrieve the token from the `OfficeRuntime.storage` item. The following code sample shows how to use the `storage.getItem` method to retrieve the token. |
64 | | - |
65 | | -```js |
66 | | -/** |
67 | | - * Read a token from storage. |
68 | | - * @customfunction GETTOKEN |
69 | | - */ |
70 | | -function receiveTokenFromCustomFunction() { |
71 | | - const key = "token"; |
72 | | - const tokenSendStatus = document.getElementById('tokenSendStatus'); |
73 | | - OfficeRuntime.storage.getItem(key).then(function (result) { |
74 | | - tokenSendStatus.value = "Success: Item with key '" + key + "' read from storage."; |
75 | | - document.getElementById('tokenTextBox2').value = result; |
76 | | - }, function (error) { |
77 | | - tokenSendStatus.value = "Error: Unable to read item with key '" + key + "' from storage. " + error; |
78 | | - }); |
79 | | -} |
80 | | -``` |
81 | | - |
82 | | -## General guidance |
83 | | - |
84 | | -Office Add-ins are web-based and you can use any web authentication technique. There is no particular pattern or method you must follow to implement your own authentication with custom functions. You may wish to consult the documentation about various authentication patterns, starting with [this article about authorizing via external services](../develop/auth-external-add-ins.md). |
| 34 | +## Dialog API |
85 | 35 |
|
86 | | -Avoid using the following locations to store data when developing custom functions: |
| 36 | +If a token doesn't exist, you should use `OfficeRuntime.displayWebDialog` to ask the user to sign in. After a user enters their credentials, the resulting access token can be stored as an item in `OfficeRuntime.storage`. |
87 | 37 |
|
88 | | -- `localStorage`: custom functions that don't use a shared runtime don't have access to the global `window` object and therefore have no access to data stored in `localStorage`. |
89 | | -- `Office.context.document.settings`: This location isn't secure and information can be extracted by anyone using the add-in. |
| 38 | +> [!NOTE] |
| 39 | +> The JavaScript-only runtime uses a dialog object that is slightly different from the dialog object in the browser runtime used by task panes. They're both referred to as the "Dialog API", but use [OfficeRuntime.displayWebDialog](/javascript/api/office-runtime#office-runtime-officeruntime-displaywebdialog-function(1)) to authenticate users in the JavaScript-only runtime, *not* [Office.ui.displayDialogAsync](/javascript/api/office/office.ui#office-office-ui-displaydialogasync-member(1)). |
90 | 40 |
|
91 | | -## Dialog box API example |
| 41 | +### Dialog box API example |
92 | 42 |
|
93 | 43 | In the following code sample, the function `getTokenViaDialog` uses the `OfficeRuntime.displayWebDialog` function to display a dialog box. This sample is provided to show the capabilities of the method, not demonstrate how to authenticate. |
94 | 44 |
|
95 | | -```JavaScript |
| 45 | +```javascript |
96 | 46 | /** |
97 | 47 | * Function retrieves a cached token or opens a dialog box if there is no saved token. Note that this isn't a sufficient example of authentication but is intended to show the capabilities of the displayWebDialog method. |
98 | 48 | * @param {string} url URL for a stored token. |
@@ -136,6 +86,64 @@ function getTokenViaDialog(url) { |
136 | 86 | } |
137 | 87 | ``` |
138 | 88 |
|
| 89 | +## OfficeRuntime.storage object |
| 90 | + |
| 91 | +The JavaScript-only runtime doesn't have a `localStorage` object available on the global window, where you typically store data. Instead, your code should share data between custom functions and task panes by using `OfficeRuntime.storage` to set and get data. |
| 92 | + |
| 93 | +### Suggested usage |
| 94 | + |
| 95 | +When you need to authenticate from a custom function add-in that doesn't use a shared runtime, your code should check `OfficeRuntime.storage` to see if the access token was already acquired. If not, use [OfficeRuntime.displayWebDialog](/javascript/api/office-runtime#office-runtime-officeruntime-displaywebdialog-function(1)) to authenticate the user, retrieve the access token, and then store the token in `OfficeRuntime.storage` for future use. |
| 96 | + |
| 97 | +### Storing the token |
| 98 | + |
| 99 | +The following examples show how to store and retrieve tokens by using `OfficeRuntime.storage`. |
| 100 | + |
| 101 | +If the custom function authenticates, then it receives the access token and will need to store it in `OfficeRuntime.storage`. The following code sample shows how to call the `storage.setItem` method to store a value. The `storeValue` function is a custom function that stores a value from the user. You can modify this to store any token value you need. |
| 102 | + |
| 103 | +```javascript |
| 104 | +/** |
| 105 | + * Stores a key-value pair into OfficeRuntime.storage. |
| 106 | + * @customfunction |
| 107 | + * @param {string} key Key of item to put into storage. |
| 108 | + * @param {*} value Value of item to put into storage. |
| 109 | + */ |
| 110 | +function storeValue(key, value) { |
| 111 | + return OfficeRuntime.storage.setItem(key, value).then(function (result) { |
| 112 | + return "Success: Item with key '" + key + "' saved to storage."; |
| 113 | + }, function (error) { |
| 114 | + return "Error: Unable to save item with key '" + key + "' to storage. " + error; |
| 115 | + }); |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +When the task pane needs the access token, it can retrieve the token from the `OfficeRuntime.storage` item. The following code sample shows how to use the `storage.getItem` method to retrieve the token. |
| 120 | + |
| 121 | +```javascript |
| 122 | +/** |
| 123 | + * Read a token from storage. |
| 124 | + * @customfunction GETTOKEN |
| 125 | + */ |
| 126 | +function receiveTokenFromCustomFunction() { |
| 127 | + const key = "token"; |
| 128 | + const tokenSendStatus = document.getElementById('tokenSendStatus'); |
| 129 | + OfficeRuntime.storage.getItem(key).then(function (result) { |
| 130 | + tokenSendStatus.value = "Success: Item with key '" + key + "' read from storage."; |
| 131 | + document.getElementById('tokenTextBox2').value = result; |
| 132 | + }, function (error) { |
| 133 | + tokenSendStatus.value = "Error: Unable to read item with key '" + key + "' from storage. " + error; |
| 134 | + }); |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +## General guidance |
| 139 | + |
| 140 | +Office Add-ins are web-based, so you can use any web authentication technique. There isn't one required authentication pattern for custom functions. Start with [Authorize to external services in Office Add-ins](../develop/auth-external-add-ins.md) for design patterns and tradeoffs. |
| 141 | + |
| 142 | +Avoid using the following locations to store data when developing custom functions: |
| 143 | + |
| 144 | +- `localStorage`: custom functions that don't use a shared runtime don't have access to the global `window` object and therefore have no access to data stored in `localStorage`. |
| 145 | +- `Office.context.document.settings`: This location isn't secure, and anyone using the add-in can extract this information. |
| 146 | + |
139 | 147 | ## Next steps |
140 | 148 |
|
141 | 149 | Learn how to [debug custom functions](custom-functions-debugging.md). |
|
0 commit comments