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

# Authorization Code Flow

> Use the OAuth 2.0 Authorization Code flow with PKCE to authenticate users against ABBYY Vantage and obtain access tokens for the Vantage API.

export const VantageRegion = ({children}) => {
  const STORAGE_KEY = "abbyy.vantage.region";
  const REGIONS = [{
    code: "eu",
    label: "Europe"
  }, {
    code: "us",
    label: "North America"
  }, {
    code: "au",
    label: "Australia / Asia-Pacific"
  }];
  const [region, setRegion] = useState("eu");
  const [open, setOpen] = useState(false);
  const containerRef = useRef(null);
  const dropdownRef = useRef(null);
  function safeGetSavedRegion() {
    try {
      const saved = typeof window !== "undefined" ? window.localStorage.getItem(STORAGE_KEY) : null;
      const valid = new Set(REGIONS.map(r => r.code));
      return saved && valid.has(saved) ? saved : "eu";
    } catch {
      return "eu";
    }
  }
  function safeSetSavedRegion(code) {
    try {
      if (typeof window !== "undefined") {
        window.localStorage.setItem(STORAGE_KEY, code);
      }
    } catch {}
  }
  function dispatchRegionChanged(code) {
    try {
      if (typeof window !== "undefined") {
        window.dispatchEvent(new CustomEvent("abbyy:region-changed", {
          detail: {
            code
          }
        }));
      }
    } catch {}
  }
  function replaceRegionInString(text, currentRegion) {
    if (typeof text !== "string") return text;
    const hostRegex = /https:\/\/vantage-(eu|us|au)\.abbyy\.com/gi;
    const tokenRegex = /https:\/\/vantage-\[region\]\.abbyy\.com/gi;
    return text.replace(hostRegex, `https://vantage-${currentRegion}.abbyy.com`).replace(tokenRegex, `https://vantage-${currentRegion}.abbyy.com`);
  }
  useEffect(() => {
    setRegion(safeGetSavedRegion());
  }, []);
  useEffect(() => {
    const root = containerRef.current;
    if (!root) return;
    const anchors = root.querySelectorAll("a[href]");
    anchors.forEach(a => {
      const href = a.getAttribute("href");
      if (href) {
        const next = replaceRegionInString(href, region);
        if (next !== href) {
          a.setAttribute("href", next);
        }
      }
    });
    const walker = typeof document !== "undefined" ? document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null) : null;
    if (walker) {
      const toUpdate = [];
      let node = walker.nextNode();
      while (node) {
        const updated = replaceRegionInString(node.nodeValue, region);
        if (updated !== node.nodeValue) {
          toUpdate.push([node, updated]);
        }
        node = walker.nextNode();
      }
      toUpdate.forEach(([textNode, value]) => {
        textNode.nodeValue = value;
      });
    }
  }, [region, children]);
  useEffect(() => {
    const root = containerRef.current;
    if (!root) return;
    const anchors = root.querySelectorAll("a[href]");
    anchors.forEach(a => {
      a.style.fontWeight = "600";
      a.style.textDecoration = "underline";
      a.style.textUnderlineOffset = "2px";
    });
  }, [region, children]);
  useEffect(() => {
    const onRegionChanged = evt => {
      const code = evt && evt.detail && evt.detail.code;
      if (!code || code === region) return;
      setRegion(code);
    };
    if (typeof window !== "undefined") {
      window.addEventListener("abbyy:region-changed", onRegionChanged);
    }
    return () => {
      if (typeof window !== "undefined") {
        window.removeEventListener("abbyy:region-changed", onRegionChanged);
      }
    };
  }, [region]);
  useEffect(() => {
    const onClickAway = e => {
      if (!dropdownRef.current) return;
      if (!dropdownRef.current.contains(e.target)) {
        setOpen(false);
      }
    };
    document.addEventListener("click", onClickAway, true);
    return () => document.removeEventListener("click", onClickAway, true);
  }, []);
  const onSelect = code => {
    setRegion(code);
    safeSetSavedRegion(code);
    dispatchRegionChanged(code);
    setOpen(false);
  };
  const current = REGIONS.find(r => r.code === region) || REGIONS[0];
  return <div className="not-prose">
      <div className="mb-4 inline-flex items-center gap-2" ref={dropdownRef}>
        <span className="text-sm text-zinc-950/80 dark:text-white/80">Tenant Region:</span>
        <div className="relative">
          <button type="button" aria-haspopup="listbox" aria-expanded={open ? "true" : "false"} onClick={() => setOpen(v => !v)} className="h-8 px-3 rounded-md bg-zinc-900/5 dark:bg-white/5 border border-zinc-950/20 dark:border-white/20 text-sm inline-flex items-center gap-2">
            <span className="text-zinc-950 dark:text-white">{current.label}</span>
            <svg width="8" height="24" viewBox="0 -9 3 24" className="transition-transform text-gray-400 overflow-visible dark:text-gray-600 ml-auto" style={{
    transform: open ? "rotate(270deg)" : "rotate(90deg)"
  }}>
              <path d="M0 0L3 3L0 6" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"></path>
            </svg>
          </button>
          {open ? <div role="listbox" className="absolute z-50 left-full top-0 ml-2 w-56 rounded-xl border border-zinc-950/20 dark:border-white/20 bg-white dark:bg-zinc-900 shadow-lg p-2">
              {REGIONS.map(r => {
    const selected = r.code === region;
    return <button key={r.code} type="button" role="option" aria-selected={selected ? "true" : "false"} onClick={() => onSelect(r.code)} className={"w-full flex items-center justify-between px-3 py-2 rounded-lg text-sm hover:bg-zinc-950/5 dark:hover:bg-white/10 text-zinc-950 dark:text-white" + (selected ? " font-medium" : "")}>
                    <span style={selected ? {
      color: "#ff2038"
    } : undefined}>{r.label}</span>
                    <span className={selected ? "ml-3" : "ml-3 invisible"} style={selected ? {
      color: "#ff2038"
    } : undefined}>✓</span>
                  </button>;
  })}
            </div> : null}
        </div>
      </div>
      <div ref={containerRef} className="prose dark:prose-invert max-w-none">{children}</div>
    </div>;
};

This authentication scheme is considered to be the most secure, since instead of directing the authentication request to the user, the application directs it to the Vantage authorization server instead. The authorization server then authenticates the user and returns the authorization code to the client.

In order to prevent the authorization code from being intercepted, this authentication scenario uses a security extension called PKCE (Proof Key for Code Exchange). This extension works as follows: each authorization request requires a cryptographic random number to be generated and stored in **code\_verifier**, which is then used to obtain a cryptographically signed value stored in **code\_challenge**. This new value is then sent to the authorization server in order to obtain an authorization code.

For more information about PKCE, visit [this link](https://datatracker.ietf.org/doc/html/rfc7636).

#### Getting the authorization code

To begin the authentication process, redirect the user to the authorize endpoint, passing the following parameters:

| Parameter                                      | Description                                                                                                                                                                     |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| client\_id                                     | The application identifier. For information on how to create a Vantage API Client (**client\_id** and **client\_secret**), see the Managing Tenant Vantage API Clients article. |
| redirect\_uri                                  | The URL of your application or website that is used to redirect the browser once access permissions have been granted.                                                          |
| response\_type=code                            | Specifies that the authorization code response type is used.                                                                                                                    |
| scope=openid permissions global.wildcard       | Specifies the permission scope.                                                                                                                                                 |
| state                                          | An arbitrary string value that will contain the authorization result in the response.                                                                                           |
| code\_challenge                                | Digitally signed value of the **code\_verifier** code (using the **code\_challenge\_method** method).                                                                           |
| code\_challenge\_method                        | The digital signature method for the **code\_verifier** code (S256).                                                                                                            |
| productId=a8548c9b-cb90-4c66-8567-d7372bb9b963 | The Vantage identifier.                                                                                                                                                         |

<Warning>
  The values for response\_type, scope, productId should be exactly as specified above. These keys, except response\_type, are subject to change. Consider keeping them in configuration.
</Warning>

Sample Request

<VantageRegion>
  ```shell wrap theme={null}
  https://vantage-us.abbyy.com/auth2/connect/authorize?client_id=client_id&redirect_uri=https%3A%2F%2Fvantage-us.abbyy.com%2Flogin-callback&response_type=code&scope=openid%20permissions%20global.wildcard&state=ef30939211cc4ecb9a7a349b855c6a10&code_challenge=tA6ayQ5VUjLX2tufAKaHh-9bTAQ4hQQY5VZAoB2kG9o&code_challenge_method=S256&productId=a8548c9b-cb90-4c66-8567-d7372bb9b963
  ```
</VantageRegion>

A parameter called redirect\_uri that contains your resource's identifier is used in Oauth 2.0 in order to allow Vantage to send the authorization code to your resource and then exchange that code for the access token, which is required for authentication in all subsequent API calls. Using this authentication method requires providing the value of the redirect\_uri parameter to ABBYY technical support in order to have it whitelisted by the administrators.

Once access permissions requested using the scope parameter have been verified to be granted, the browser is redirected to a special web page set up by the Vantage server. This web page has a dialog window that is used to undergo authorization using your account. This page should be opened using a browser that has a visible address bar, which will let you verify the page URL and the state of the connection's SSL certificate.

If your email address is connected to several accounts in different tenants, you will be asked to select a tenant and enter your password after you have specified your email address. You can also pass your tenant identifier (the tokenId parameter) directly using one of the following resources:

<VantageRegion>
  ```shell wrap theme={null}
  https://vantage-us.abbyy.com/auth2/{tenantId}/connect/authorize?client_id=client_id&redirect_uri=external_app_redirect_uri&response_type=code
  &scope=openid%20permissions%20global.wildcard&state=state&code_challenge=code_challenge
  &code_challenge_method=S256&productId=a8548c9b-cb90-4c66-8567-d7372bb9b963
  ```
</VantageRegion>

or

<VantageRegion>
  ```shell wrap theme={null}
  https://vantage-us.abbyy.com/auth2/connect/authorize?client_id=client_id&redirect_uri=external_app_redirect_uri&response_type=code
  &scope=openid%20permissions%20global.wildcard&state=state&code_challenge=code_challenge
  &code_challenge_method=S256&productId=a8548c9b-cb90-4c66-8567-d7372bb9b963&tenantId=tenantId
  ```
</VantageRegion>

You will be required to enter the password for your tenant account. Once you have entered your credentials, authorization is completed server-side, the application is granted access to the Vantage API, and you receive the authorization code in the response to your request.

Please be aware that if a site or application uses this authentication type, Vantage users will provide access to the Vantage API on their behalf to the site or app that you are adding to the list of allowed redirect URL's. To provide access to the site or app, users will be asked to authenticate in Vantage using their login and password. Once a user is authenticated, the site or app will be granted the following permissions:

* Managing data catalogs in the Vantage tenant on behalf of the user,
* Accessing skills in the Vantage tenant on behalf of the user,
* Creating and accessing Vantage transactions on behalf of the user.

The site or app will not be able to change user's password, change the list of users in a Vantage tenant, or edit skills. Only access to the Vantage API will be provided. The user will not be able to revoke access once it has been granted.

#### Getting the authorization token

Once you have obtained the authorization code, you have one minute to exchange it for the access token. Use a POST request to the token endpoint with `application/x-www-form-urlencoded` data.

Request body parameters:

| Parameter                                                | Description                                                                                      |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| code\_verifier                                           | The code that you have generated. Needed to confirm the initiation of the authorization request. |
| client\_id                                               | The application identifier.                                                                      |
| client\_secret                                           | Secure application key.                                                                          |
| code                                                     | Your authorization code obtained from the server.                                                |
| redirect\_uri                                            | The redirect URL used in the authorize step.                                                     |
| grant\_type=authorization\_code                          | Specifies that the authorization code grant type is used.                                        |
| scope=openid permissions global.wildcard offline\_access | Specifies the permission scope. To get a refresh token, add **offline\_access** to the scope.    |

Sample request:

For Windows:

<VantageRegion>
  ```shell theme={null}
  curl --location --request POST "https://vantage-eu.abbyy.com/auth2/connect/token" \
    --data-urlencode "code_verifier=code_verifier" \
    --data-urlencode "client_id=client_id" \
    --data-urlencode "client_secret=client_secret" \
    --data-urlencode "code=authorization code" \
    --data-urlencode "redirect_uri=external app redirect uri" \
    --data-urlencode "grant_type=authorization_code"
  ```
</VantageRegion>

For Linux:

<VantageRegion>
  ```shell theme={null}
  curl --location --request POST 'https://vantage-eu.abbyy.com/auth2/connect/token' \
    --data-urlencode 'code_verifier=code_verifier' \
    --data-urlencode 'client_id=client_id' \
    --data-urlencode 'client_secret=client_secret' \
    --data-urlencode 'code=authorization code' \
    --data-urlencode 'redirect_uri=external app redirect uri' \
    --data-urlencode 'grant_type=authorization_code'
  ```
</VantageRegion>

The server's response to your request will contain the access token:

```json theme={null}
{
  "id_token": "<redacted>",
  "access_token": "<redacted>",
  "expires_in": 86400,
  "token_type": "Bearer",
  "refresh_token": "<redacted>",
  "scope": "openid permissions global.wildcard offline_access legacy.client"
}
```

For more information about Authorization Code Flow, visit [this link](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1).

For each flow, the **access\_token** key contains the token, while the **expires\_in** key specifies how soon the token will expire (in seconds). By default, access token lifetime is 24 hours (for more information, see [Token lifetimes](#token-lifetimes). Add the following authorization header to all your requests and replace `token` with the value you received:

```shell theme={null}
-H "Authorization: Bearer token"
```

Note that you can obtain several tokens using the same account. For more information about the authorization token, visit [this link](https://datatracker.ietf.org/doc/html/rfc6749#section-7.1).

#### Getting the refresh token

If the `Allow issuing refresh tokens to refresh access tokens` option was enabled when configuring the Vantage API client and the request for getting the access token contained the `scope=openid permissions global.wildcard offline_access` parameter, you will also receive an additional refresh token in the response. Once you have a refresh token, you can refresh the access token using a POST request to the token endpoint with the following parameters:

| Parameter                  | Description                                          |
| -------------------------- | ---------------------------------------------------- |
| client\_id                 | The application identifier.                          |
| client\_secret             | A secure application key.                            |
| refresh\_token             | Your refresh token obtained from the server.         |
| grant\_type=refresh\_token | Specifies that the refresh token grant type is used. |

Sample request:

For Windows:

<VantageRegion>
  ```shell theme={null}
  curl --location --request POST "https://vantage-eu.abbyy.com/auth2/connect/token" \
    --data-urlencode "client_id=client_id" \
    --data-urlencode "client_secret=client_secret" \
    --data-urlencode "refresh_token=refresh_token" \
    --data-urlencode "grant_type=refresh_token"
  ```
</VantageRegion>

For Linux:

<VantageRegion>
  ```shell theme={null}
  curl --location --request POST 'https://vantage-eu.abbyy.com/auth2/connect/token' \
    --data-urlencode 'client_id=client_id' \
    --data-urlencode 'client_secret=client_secret' \
    --data-urlencode 'refresh_token=refresh_token' \
    --data-urlencode 'grant_type=refresh_token'
  ```
</VantageRegion>

#### Token lifetimes

Access and refresh tokens are configured to have the following lifetimes:

* **Access token lifetime:** Defines the time period during which the issued access token allows user access to Vantage. The default lifetime of an access token is 24 hours.
* **Refresh token lifetime:** Defines the absolute time period starting from the issuance of the first access token during which the issued refresh token can be used to renew the access token. The default lifetime of an refresh token is 30 days.
