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

# Set up OAuth 2.0 On-Behalf-Of token exchange with Okta as your IdP

export const Alert = ({type, title, children}) => {
  const getIcon = () => {
    switch (type) {
      case 'info':
        return "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M10 0C4.477 0 0 4.477 0 10s4.477 10 10 10 10-4.477 10-10S15.523 0 10 0zm0 15c-.552 0-1-.448-1-1s.448-1 1-1 1 .448 1 1-.448 1-1 1zm1-3H9V6h2v6z' fill='%230099FF'/%3E%3C/svg%3E";
      case 'success':
        return "data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0C4.477 0 0 4.477 0 10s4.477 10 10 10 10-4.477 10-10S15.523 0 10 0zm4.293 6.293L9 11.586 5.707 8.293c-.391-.391-1.024-.391-1.414 0s-.391 1.024 0 1.414l4 4c.391.391 1.024.391 1.414 0l6-6c.391-.391.391-1.024 0-1.414s-1.024-.391-1.414 0z' fill='%230CC26D'/%3E%3C/svg%3E";
      case 'warning':
        return "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHhtbDpzcGFjZT0ncHJlc2VydmUnIHdpZHRoPScxMDgwJyBoZWlnaHQ9JzEwODAnPjxyZWN0IHdpZHRoPScxMDAlJyBoZWlnaHQ9JzEwMCUnIGZpbGw9J3RyYW5zcGFyZW50Jy8+PHBhdGggZD0nTTEzLjc5NCAxMC43NSA4LjMgMS4yNWExLjUgMS41IDAgMCAwLTIuNiAwbC01LjQ5NCA5LjVBMS40OTQgMS40OTQgMCAwIDAgMS41IDEzaDExYTEuNDkzIDEuNDkzIDAgMCAwIDEuMjk0LTIuMjVNNi41IDUuNWEuNS41IDAgMCAxIDEgMFY4YS41LjUgMCAwIDEtMSAwek03IDExYS43NS43NSAwIDEgMSAwLTEuNS43NS43NSAwIDAgMSAwIDEuNScgc3R5bGU9J3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7ZmlsbDojZmY5ZjM1O2ZpbGwtcnVsZTpub256ZXJvO29wYWNpdHk6MScgdHJhbnNmb3JtPSd0cmFuc2xhdGUoLjAyIDE5LjMwNSlzY2FsZSg3Ny4xNCknLz48L3N2Zz4=";
      case 'danger':
        return "data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 0C4.477 0 0 4.477 0 10s4.477 10 10 10 10-4.477 10-10S15.523 0 10 0zm5.707 4.293L10 9.586 4.293 4.293c-.391-.391-1.024-.391-1.414 0s-.391 1.024 0 1.414L8.586 11l-5.707 5.293c-.391.391-.391 1.024 0 1.414s1.024.391 1.414 0L10 12.414l5.707 5.293c.391.391 1.024.391 1.414 0s.391-1.024 0-1.414L11.414 11l5.707-5.293c.391-.391.391-1.024 0-1.414s-1.024-.391-1.414 0z' fill='%23F45252'/%3E%3C/svg%3E";
      case 'note':
        return "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M10 0C4.477 0 0 4.477 0 10s4.477 10 10 10 10-4.477 10-10S15.523 0 10 0zm0 15c-.552 0-1-.448-1-1s.448-1 1-1 1 .448 1 1-.448 1-1 1zm1-3H9V6h2v6z' fill='%230099FF'/%3E%3C/svg%3E";
      default:
        return "";
    }
  };
  return <div className={`alert alert--${type}`}>
      <div className="alert-icon" style={{
    backgroundImage: `url("${getIcon()}")`,
    backgroundRepeat: 'no-repeat',
    backgroundPosition: 'center center',
    backgroundSize: '20px',
    width: '24px',
    height: '24px',
    position: 'absolute',
    left: '16px',
    top: '16px'
  }} />
      <div className="alert-content">
        {title && <div className="alert-title">{title}</div>}
        <div className="alert-body">{children}</div>
      </div>
    </div>;
};

This guide describes how to configure Okta as an authorization server for your [REST](/integrations/integrations-library/rest-api) or [GraphQL](/integrations/integrations-library/graphql) based backend API.

With this auth method, Superblocks will be able to perform a machine-to-machine token exchange to get an access token for your backend API without losing context who is making the request in your Superblocks app. This lets your API perform auth checks using the user's permissions without forcing your user through a second login flow for your backend API.

## Prerequisites

To follow this guide, you'll need:

* An Okta account with the following permissions:
  * [API Access Management Administrator](https://help.okta.com/okta_help.htm?type=\&locale=en\&id=csh-administrators-api-access-mgmt-admin)
  * [Application Administrator](https://help.okta.com/en-us/content/topics/security/administrators-app-admin.htm?cshid=csh-administrators-app-admin)
* An existing Superblocks SSO configuration using [Okta OIDC](/admin/org-administration/auth/single-sign-on/okta#create-an-oidc-integration)
* A REST or GraphQL-based backend API

<Alert type="warning">
  If your Superblocks SSO currently uses a SAML-based flow, please reach out to our [support team](/enterprise/support/help) for assistance migrating to an OIDC-based log-in flow
</Alert>

## Token exchange flow

<img src="https://mintcdn.com/superblocks/TqcwM8ac6ozIt6Fv/images/integrations/authentication/obh-token-exchange-okta.png?fit=max&auto=format&n=TqcwM8ac6ozIt6Fv&q=85&s=d60a2785927de0189d97a5a3a66b30be" alt="On-Behalf-Of Token Exchange flow sequence diagram" width="2304" height="796" data-path="images/integrations/authentication/obh-token-exchange-okta.png" />

<Alert type="info">
  **Note**: This flow assumes the user is already logged into Superblocks
</Alert>

When using this flow:

1. Your user will log in to Superblocks using your [Okta OIDC app](/admin/org-administration/auth/single-sign-on/okta#create-an-oidc-integration)
2. When the user executes an API, a request is sent from the browser to the Superblocks Agent that includes the user's Okta JWT
3. The API includes a step to make a request to your backend API. The Superblocks Agent will make a request to your [Okta authorization server](#create-an-authorization-server) to exchange the user’s Okta JWT for a new token intended for your backend API
4. The Okta authorization server validates the user’s JWT and then grants a new access token with scopes that allows Superblocks to make requests to your backend API. The new access token retains the user context so your backend API knows on whose behalf the request is made.
5. The Superblocks Agent makes a request to your backend API and includes the new access token

For more details on this token exchange in Superblocks, see our docs on the [OAuth 2.0 - On-Behalf-Of Token Exchange](/integrations/auth/oauth-20#on-behalf-of-token-exchange) auth method.

## Setup instructions

The following instructions show how to configure Okta & Superblocks to perform the token exchange.

### Create an API in Okta

To perform the token exchange, you'll need to create an API application that the Superblocks Agent will use to act as an OAuth client for your backend API.

1. Log in to Okta and go to the **Admin Console**
2. Navigate to **Applications** → **Applications**
3. Click **Create App Integration**
4. Select **API Services** followed by **Next**
5. Name the app something like **Superblocks Integration** and click **Save**
6. Click **Edit** in the **General Settings** section of the **General** tab
7. Uncheck the checkbox for **Require Demonstrating Proof of Possession (DPoP) header in token requests**
8. Check the checkbox for **Token Exchange** and click **Save**
9. Make a note of the `Client ID` in the **Client Credentials** section and the `Client Secret` in the **CLIENT SECRETS** section

### Create an authorization server

During the token exchange, the Superblocks Agent exchanges the user's OpenID access token granted during log in with an [Okta Authorization Server](https://developer.okta.com/docs/guides/customize-authz-server/main) configured to issue tokens for our backend API.

#### Create the authorization server

1. In the Admin Console, go to **Security** → **API**
2. On the **Authorization Servers** tab, click **Add Authorization Server**
3. Enter a **Name**, **Audience**, and **Description** for the authorization server

   <Alert type="info">
     **Note**: The **Audience** value specified will be set as the `aud` claim of the access token sent to your backend API. The **Audience** property should be set to the URI expected by your API.
   </Alert>

#### Add custom scopes & claims

1. From the authorization server, select the **Scopes** tab
2. Click **Add scopes** and add any custom scopes your backend API requires
3. Click on the **Claims** tab
4. Click **Add claim** and configure any custom claims you want to include on the access token

#### Create access policies and rules

1. From the authorization server, select the **Access Policies** tab and click **Add Policy**
2. In the **Add Policy** dialog that appears, enter the following:
   * **Name**: Access Superblocks
   * **Description**: Enter a description
   * **Assign to**: Select **The following clients** and search for your organization's Superblocks SSO application
3. Click **Create Policy**
4. Click **Add Rule** and in the dialog that appears, enter the following:
   * **Name**: Superblocks App to Agent
   * **AND Scopes requested**: Select **The following scopes** and enter `openid`
5. Click **Create rule**
6. Repeat steps 1 - 5 to create a policy and a rule that lets the Superblocks Agent talk to your backend API.\
   Use the following values for the **policy**:

   * **Name**: Access Backend API
   * **Assign to**: Select **The following clients**, start typing the name of the [API](#create-an-api-in-okta) that you created earlier

   Use the following values for the **rule**:

   * **Name**: Agent to Backend API
   * **AND Scopes requested**: Select **The following scopes**, and select any of the [custom scopes](#add-custom-scopes--claims) you configured previously
   * **AND Refresh token lifetime is**: Unlimited (this is recommmended but not required)

Learn more about how to [Create an Okta Authorization Server](https://developer.okta.com/docs/guides/customize-authz-server/main/#create-an-authorization-server)

### Update SSO metadata

Superblocks SSO by default uses your Okta [Org Authorization Server](https://developer.okta.com/docs/concepts/auth-servers/#org-authorization-server). To use token exchange, we'll need to update your SSO configuration to use a Custom Authorization Server.

To do this, we will need the `.well-known/openid-configuration` URL of your Authorization Server.

To locate this URL:

1. Go to the **Settings** tab of your Authorization Server
2. Copy the **Metadata URI** shown in the **Settings** section
3. Replace `oauth-authorization-server` with `openid-configuration`
4. Send this link to [support@superblocks.com](mailto:support@superblocks.com) with the Subject **Update Okta SSO to use Token Exchange**

<Alert type="info">
  If your backend uses a micro-services architecture that has multiple APIs, or you plan on using token exchange for your backend API as well as services like [Snowflake](/integrations/integrations-library/snowflake), make sure you've added this server as a [trusted server](https://help.okta.com/en-us/content/topics/security/api-add-trusted-servers.htm) to all other auth servers you'll use in Superblocks.
</Alert>

### Update your integration

Once you've gotten confirmation from Superblocks that we've updated your SSO to use the new Authorization Server, you're ready to configure your Integration. To do so:

1. Navigate to the **Integrations** page and search for your [REST](/integrations/integrations-library/rest-api) or [GraphQL](/integrations/integrations-library/graphql) API

2. Select **OAuth2 - On-Behalf-Of Token Exchange** as the **Authentication** method

3. Choose **Login Identity Provider** as the **Subject token source**

4. Specifying the following configuration values:

   | <div style={{width: 150 }}>Field</div> | Required                                   | Description                                                                                                                                                  |
   | -------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
   | **Token URL**                          | <span className="table-checkmark">✓</span> | The `token_endpoint` found in your [Authorization Server](#create-an-authorization-server)'s `{SERVER}/.well-known/oauth-authorization-server` metadata file |
   | **Client ID**                          | <span className="table-checkmark">✓</span> | The `client_id` of the [API](#create-an-api-in-okta) created earlier                                                                                         |
   | **Client secret**                      | <span className="table-checkmark">✓</span> | The `client_secret` of the [API](#create-an-api-in-okta) created earlier                                                                                     |
   | **Audience**                           | <span className="table-x">✗</span>         | Your [Authorization Server](#create-an-authorization-server)'s **Audience**                                                                                  |
   | **Scopes**                             | <span className="table-x">✗</span>         | Any custom scopes you configured for your authorization server                                                                                               |

5. Use the [`oauth` object](/integrations/auth/oauth-20#the-oauth-object) in **Headers** or **Params** to define how the access token returned by the authorization server should be sent to your API

<Alert type="warning">
  Okta Authorization Servers can only return an `access_token`, not an `id_token`. For this reason, `oauth.idToken` and `oauth.tokenDecoded` aren't available when using this auth method.
</Alert>

## Testing & troubleshooting

### Test your integration

With your integration updated to use your Okta authorization server to issue access tokens, you're ready to test it in a Backend API.

1. In an Application create a new Backend API
2. Add a step that uses your Integration
3. Configure the step to make a request to your API
4. Click **Run API**

If everything is working properly, you should see the step respond as it would if you made a cURL request with your own access token to the API.

### Troubleshooting

The easiest way to troubleshoot authorization issues is by inspecting the access token that Superblocks is sending to your API. To do this:

1. Make a copy of your Integration
2. Replace the **Base URL** with a API resting service like [webhook.site](https://webhook.site/) or [Postman Echo](https://learning.postman.com/docs/developer/echo-api/)
3. Add an **Authorization** header with the value `{{ oauth.token }}`
4. Save the Integration
5. Build a Backend API that uses this "echo" integration
6. Run the API and copy the access token from the authorization header
7. Use a tool like [JWT](https://jwt.io/) to inspect the token

### Common errors

See the below guide for known error conditions, why they happen, and how to address them.

| <div style={{width: 225}}>Error message</div> | Why it's happening                                                                                                                                                                                               | Resolution                                                                                                                                                                             |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Could not find identity provider token`      | Your organization either doesn't use SSO or it's configured in a way that doesn't support token exchange                                                                                                         | Follow docs to set up [Okta SSO](/admin/org-administration/auth/single-sign-on/okta) or contact [support@superblocks.com](mailto:support@superblocks.com) to update your configuration |
| `Identity provider token expired`             | Your Okta session has expired so the authorization server won't issue an access token                                                                                                                            | Refresh your browser, you should be prompted to reauthenticate. If you're not, log out and back in.                                                                                    |
| `Could not find a user JWT`                   | The Superblocks Agent doesn't have a user JWT so can't extract a `subject_token` to send to Okta. It most likely is occurring because the integration is being used in a Workflow, Scheduled Job, or public App. | Refactor your code to use the Integration in a Backend API                                                                                                                             |
| `Token exchange failed`                       | Superblocks couldn't successfully complete the token exchange with the Okta authorization server.                                                                                                                | See the additional error details provided by Okta. You may also be able to find additional error information in your Okta system logs.                                                 |
