Outbound Apps

Descope Outbound Apps let you securely connect your users to third-party providers for specialized actions and additional permissions—without relying on those providers as primary authentication methods. Think of them as an extension of OAuth social login. You can define default scopes, progressively request new scopes, and rely on Descope to automatically manage and refresh access tokens on your behalf.

Potential Use Cases

  1. Incremental Scopes
    Start with minimal OAuth scopes (e.g., OpenID, email, profile), then request elevated access—like reading contacts or posting videos—only when needed, keeping the initial sign-up flow simple.

  2. New Provider, Same User
    Even if you don't offer LinkedIn as a primary authentication method, you can still request LinkedIn-specific permissions later (e.g., posting to a user's timeline), all without changing your core login experience.

  3. AI Agents
    If you're building AI agents that require permissions to interact with external APIs, Outbound Apps handle secure token management and refresh cycles. Your tools/functions can reliably access user tokens whenever they need to invoke AI-powered features or process user data.

Currently, Outbound Apps only support OAuth-based providers.

Creating an Outbound App

To configure an outbound application within Descope, navigate to the Outbound Apps section of the console and select + Outbound App.

You can then select a custom connection, or one of our preconfigured applications within the outbound app library.

Creating an outbound app in Descope

Once you have created your outbound application, you can configure it. The configuration is split into several sections: Outbound App Details, Account Information, Additional Settings, and Token Management.

This example will walk through configuring Google Contacts as an outbound application.

Outbound App Details

Within this section, you can find and configure the information regarding your application below.

  • Logo (Optional): You can upload a logo for the outbound app by clicking the edit button on the logo. The "Connect To" consent button within your flows for the outbound app will automatically utilize the uploaded logo.
  • Outbound Name (Required): This is the configurable name of the application.
  • Description (Optional): This is the chosen description of your application, and it is editable.
  • Outbound App ID (Required): This is configurable only during the creation of the outbound application. Once the initial configuration is complete, this field will not be editable.

Configuring an outbound app's details in Descope

Account Information

Within this section, you will define the connection settings and scopes for your outbound application.

Connection Settings

Here, you will configure the connection to the outbound app provider. This example shows one of the preconfigured applications (Google Contacts).

  • Client ID (Required): The ID from the provider when creating your authentication account
  • Client Secret (Required): The secret from the provider when creating your authentication account
  • Callback Domain (Optional): The domain to use for callbacks. This will default to the configured domain within project settings.
  • Callback URL for app registration (Pre-defined): To use a custom domain in your OAuth verification screen, configure a custom domain on the Project page.

Note

It is important to note that the callback URL for outbound applications differs from the callback URL of OAuth authentication methods and will require you to add the additional URL to your application's callback domains list.

Configuring an outbound app's connection settings in Descope

Scopes

Within this section, you will configure the scopes to associate with the outbound application. These configured scopes must also be configured on your provider's application.

Note

Where applicable, within non-custom applications, Descope prepopulates example scopes for the outbound application; however, Descope also links to the provider's scope documentation to allow you to review and refine the scopes requested further.

Example: Google Contacts Application

By default, Google Contacts prompts for full access:

  • Scope: https://www.googleapis.com/auth/contacts
  • Description: See, edit, download, and permanently delete your contacts

However, you can switch to read-only access by using:

  • Scope: https://www.googleapis.com/auth/contacts.readonly

This adjustment is shown in the example screenshot below:

Configuring an outbound app's scopes in Descope

In order to use the Google Contacts APIs with this scope however, you must also configure the https://www.googleapis.com/auth/contacts.readonly scope on your Google application.

See the example below:

Configuring additional scopes on a Google Oauth application to be used with outbound apps in Descope

Additional Settings

Within the additional settings section, you can configure more details for how your application behaves on successful consent, authorization, and token endpoint configuration.

Note

When using an application from the outbound app library, the authorization and token endpoint are prepopulated. These prepopulated endpoints should work as intended and not need to be altered during the app creation.

  • Redirect URL (Optional): The default redirect URL after a successful connection. This value will be overridden when using flows or specifying the redirect URL in the API/SDK call.
  • Authorization Endpoint (Required): The endpoint to request authorization from the user.
  • Token Endpoint (Required): The endpoint to exchange the authorization code for an access token.

Configuring an outbound app's additional settings in Descope

Token Management

Within the token management tab, you can view details of the users who have granted consent to the outbound app.

  • ID: System-generated ID paring that user's consent to the application.
  • App ID: The configured application ID which coincides with the token ID.
  • Associated User: The user ID of the user who's associated with the consent.
  • Scopes: The consented scopes correlate to the user's consent to the application.
  • Access Token Expiration: Expiration of the current access token for the user's consent.
  • Refresh Token: Boolean True/False whether a refresh token is available.
  • Last Refreshed: The last time the user's access token was refreshed.
  • Last Refresh Error: If applicable, the last error encountered while trying to refresh the user's access token.
  • Token Subject: The user reference on the provider side. For this example, it is associated with the unique user ID of the user's Google account.
  • Access Token Type: Specifies the format or method the access token uses, such as Bearer or MAC, which determines how it is used for authentication and authorization.
  • Tenant ID: The tenant ID of the tenant associated with the consent.

Viewing an outbound applications token management Descope

Token Usage

Provider token usage within outbound applications is very similar to using provider tokens from OAuth authentication methods.

Descope securely stores and manages the access and refresh tokens, and will refresh the access token as needed.

Through Descope's API, you can fetch the user's tokens to use against the provider's API.

The below example provides a brief description of how you can use the token generated from the Google Contacts use case.

You will fetch the user's token using the Descope API with your Project ID and Management Key.

curl -X POST "https://api.descope.com/v1/mgmt/outbound/app/user/token" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <PROJECT_ID:MANAGEMENT_KEY>" \
  -d '{
  "appId": "google-contacts",
  "userId": "xxxxx",
  "scopes": [
    "https://www.googleapis.com/auth/contacts.readonly"
  ],
  "options": {
    "withRefreshToken": true,
    "forceRefresh": true
  }
}'

The returned response includes the user's token details, like the one below.

{
  "token": {
    "id": "xxxx",
    "appId": "google-contacts",
    "userId": "xxxx",
    "tokenSub": "",
    "accessToken": "ya29.xxxx",
    "accessTokenType": "Bearer",
    "accessTokenExpiry": "1741107113",
    "hasRefreshToken": true,
    "refreshToken": "xxxx",
    "lastRefreshTime": "1741103514",
    "lastRefreshError": "",
    "scopes": [
      "https://www.googleapis.com/auth/contacts.readonly"
    ]
  }
}

You could then query against the Google API using the received access token. Below is an example Python script that fetches the user's contacts.

import json
import requests
 
access_token = "ya29.xxxx"
user_mail = "user@example.com"
request_url = "https://people.googleapis.com/v1/people/me/connections"
params = {
    'personFields': 'names,emailAddresses',  # Specify valid fields
    'pageSize': 100  # Adjust as needed
}
headers = {"Authorization": f"Bearer {access_token}"}
 
response = requests.get(request_url, headers=headers, params=params)
 
# Check the response status code
if response.status_code == 200:
    try:
        # Parse the JSON response
        response_array = response.json()
        if 'connections' in response_array and response_array['connections']:
            # Pretty print the JSON response
            print('Response:', json.dumps(response_array['connections'], indent=4))
        else:
            print('No contacts found.')
    except requests.exceptions.JSONDecodeError:
        print('Error decoding JSON:', response.text)
else:
    print(f'Error: {response.status_code}')
    print('Response Text:', response.text)

Here is an example of the returned data for the user's contacts.

[
    {
        "resourceName": "people/xxxx",
        "etag": "xxxx",
        "names": [
            {
                "metadata": {
                    "primary": true,
                    "source": {
                        "type": "CONTACT",
                        "id": "xxxx"
                    },
                    "sourcePrimary": true
                },
                "displayName": "Joe Person",
                "familyName": "Person",
                "givenName": "Joe",
                "displayNameLastFirst": "Person, Joe",
                "unstructuredName": "Joe Person"
            }
        ],
        "emailAddresses": [
            {
                "metadata": {
                    "primary": true,
                    "source": {
                        "type": "CONTACT",
                        "id": "xxxx"
                    }
                },
                "value": "joe@person.net"
            }
        ]
    },
    ...
]
Was this helpful?

On this page