> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zapier.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Selecting an Authentication

> Support users in selecting 3rd party authentications, either through an existing authentication or by adding new.

An Authentication is a set of user credentials for an [App](/powered-by-zapier/api-reference/apps/get-apps-v2) that is stored securely by Zapier. When required, a user must select which of the Authentications they have for that App (they may have multiple) that they would like to use when an Action executes.

<Note>
  [Authentication
  Schema](/powered-by-zapier/api-reference/common-types/authentication)
</Note>

We can fetch a list of Authentications available for an App by making a request to the [`/authentications endpoint`](/powered-by-zapier/api-reference/authentications/get-authentications):

```js theme={null}
// GET /authentications?app=4b3920d6-1d5a-4071-b837-9383dc511b80
{
  "data": [
    {
      "type": "authentication",
      "id": "49509",
      "app": "4b3920d6-1d5a-4071-b837-9383dc511b80",
      "title": "SuperExampleCRM (wade@zapier.com)",
      "is_expired": false
    },
    {
      "type": "authentication",
      "id": "96983",
      "app": "4b3920d6-1d5a-4071-b837-9383dc511b80",
      "title": "SuperExampleCRM (bryan@zapier.com)",
      "is_expired": false
    }
  ]
}
```

Our user can then select one of these Authentications to use with an Action.

## When no Authentications exist

It's possible that the user doesn't have *any* Authentications for an App they've picked, as in every case when it's a new Zapier account. In these cases the `/authentications` endpoint will return an empty list under the `data` key. In this scenario, we should direct the user to the url provided by the `/apps` endpoint under the `links.connect_new_authentication` key to add a new Authentication.

This is also the best approach to take if you want to offer the user the option to use a new Authentication with this Action, even if they already have Authentications available. (e.g. If the user wants to use a different SuperExampleCRM account than the ones already linked to Zapier).

<Note>
  If `links.connect_new_authentication` is `null`, then this app doesn't require
  authentication, and `null` should be passed instead of a valid id. Read more
  about that
  [below](/powered-by-zapier/zap-creation/selecting-an-authentication#when-authentication-is-not-required).
</Note>

<Warning>
  Because `postMessage` requires a handler to send the message to, any portion
  of the flow that breaks `window.opener` for Zapier will result in no message
  being sent. In such cases, polling the [`/authentications
      endpoint`](/powered-by-zapier/api-reference/authentications/get-authentications)
  is the best option to retrieve the new authentication ID. Zapier cannot
  override third-party flows to force an opener to be persisted, and third-party
  code may change at any time. The code sample below implements this fallback:
  do not rely on `postMessage` alone.
</Warning>

### Directing the user to create a new Authentication

The best way to use this `links.connect_new_authentication` link is as follows:

<Steps>
  <Step title="Snapshot the user's existing authentications for the app">
    Before opening the popup, call the [`/authentications
            endpoint`](/powered-by-zapier/api-reference/authentications/get-authentications)
    and record the IDs already returned. The fallback in a later step uses this
    snapshot to detect the new authentication once it is created.
  </Step>

  <Step title="Open the `links.connect_new_authentication` link in a popup">
    In this popup, the user will be prompted to authenticate with the app, and to allow Zapier to access that app.
  </Step>

  <Step title="Create an event listener to listen for `zapier.popup.close` messages from that popup">
    A message with that type will be posted when the auth flow in the popup is complete. Treat this as the fast path: it does not fire if the popup loses its `window.opener` reference, which some third-party auth flows do.
  </Step>

  <Step title="Poll `/authentications` as a fallback while the popup is open">
    Some third-party sites sever `window.opener` during their own redirect chain, so the `postMessage` in the previous step never arrives. Poll the same [`/authentications
            endpoint`](/powered-by-zapier/api-reference/authentications/get-authentications)
    on an interval and resolve as soon as an authentication ID appears that was not in the snapshot from step 1. This path never depends on `window.opener`, so it works even when `postMessage` cannot be delivered.
  </Step>

  <Step title="From either path, retrieve the new `authentication_id`">
    Afterwards, use that `authentication_id` to continue the workflow. The full implementation below combines all of these steps, plus a dismissal check on `popup.closed` and an absolute timeout so an abandoned popup cannot hang the flow forever.

    ```js theme={null}
    // `fetchAuthentications` should call GET /authentications?app=<id> and
    // return the `data` array from the response.
    async function connectNewAuthentication(
      app,
      { fetchAuthentications, pollIntervalMs = 2000, pollTimeoutMs = 5 * 60 * 1000 } = {},
    ) {
      if (!app.links.connect_new_authentication) return null;

      // 1. Snapshot existing authentications before opening the popup, so the
      // fallback can detect "a new one appeared" on its own, with no message
      // from the popup required.
      const before = new Set((await fetchAuthentications()).map((a) => a.id));

      // 2. Open a popup window to the `links.connect_new_authentication` url.
      const authPopup = window.open(
        app.links.connect_new_authentication,
        "_blank",
        "width=1280,height=1024",
      );
      if (!authPopup) {
        alert("Please allow popups to continue.");
        return;
      }

      return new Promise((resolve) => {
        let settled = false;

        function cleanup() {
          settled = true;
          removeEventListener("message", onMessage);
          clearInterval(closedPoll);
          clearInterval(authPoll);
          clearTimeout(giveUpTimer);
          try {
            authPopup.close();
          } catch {
            // Ignore: the popup may already be closed, or `window.opener` may
            // have been severed by the third-party flow.
          }
        }

        // 3. Fast path: resolve as soon as the popup posts a `zapier.popup.close`
        // message with the new authentication_id.
        function onMessage(event) {
          if (settled || event.origin !== "https://zapier.com") return;
          const action = event.data;
          if (action?.type === "zapier.popup.close") {
            cleanup();
            resolve(action.authentication_id);
          }
        }
        addEventListener("message", onMessage);

        // Dismissal signal: if the user closes the popup without completing
        // auth, give the fallback poll a couple more cycles, then resolve with
        // no authentication.
        const closedPoll = setInterval(() => {
          if (settled) return;
          try {
            if (authPopup.closed) {
              clearInterval(closedPoll);
              setTimeout(() => {
                if (!settled) {
                  cleanup();
                  resolve(undefined);
                }
              }, pollIntervalMs * 2);
            }
          } catch {
            // `authPopup.closed` can throw if `window.opener` was severed.
            // The authentications poll below is the fallback for this case.
            clearInterval(closedPoll);
          }
        }, 500);

        // 4. Fallback path: poll `/authentications` for an ID that was not in
        // the snapshot from step 1. This never touches `window.opener`, so it
        // works even when `postMessage` cannot be delivered.
        const authPoll = setInterval(async () => {
          if (settled) return;
          try {
            const current = await fetchAuthentications();
            const created = current.find((a) => !before.has(a.id));
            if (created) {
              cleanup();
              resolve(created.id);
            }
          } catch {
            // Ignore transient fetch errors; the next tick tries again.
          }
        }, pollIntervalMs);

        // Absolute timeout so an abandoned popup cannot hang the flow forever.
        const giveUpTimer = setTimeout(() => {
          if (!settled) {
            cleanup();
            resolve(undefined);
          }
        }, pollTimeoutMs);
      });
    }
    ```
  </Step>
</Steps>

<Tip>
  Looking to add an authentication to your own app? You can supply auth details
  directly and streamline the process. Check out [Adding App
  Authentications](/powered-by-zapier/managing-app-authentication/adding-app-authentications).
</Tip>

## When Authentication is not required

Some apps don't require authentication at all - like Webhooks. You'll know this is the case when fetching the app and it's not possible to add a new authentication.

```js Sample response from /apps theme={null}
...
"links": {
          "connect_new_authentication": null
        },
...
```

When creating Zap workflows or running Actions with these apps, `null` should be passed in place of a valid authentication id;

<CodeGroup>
  ```js Sample POST to /inputs theme={null}
  // POST https://api.zapier.com/v2/actions/core:8yjfgwyq03zskh3LOe9jPa5dOeW/inputs
  {
    "data": {
      "authentication": null,
      "inputs": {}
    }
  }
  ```

  ```js Sample POST to /zaps theme={null}
  // POST https://api.zapier.com/v2/zaps
  ...
  "steps": [
        ...
        {
          "action": "core:3ZYFzZKkjbDK2AwQopVqrZWL9pK",
          "inputs": {
            "url": "https://greatWebhooks.com/myWebhook"
          },
          "authentication": null
        }
      ]
  ...
  ```
</CodeGroup>
