Creating a Connection

You can create a Connection in Descope using three different methods:

  1. Manually in the Console: Navigate to the Connections section of the console and select + Connection. You can then select a custom connection, or one of our preconfigured connections within the library.
  2. Programmatically via APIs/SDKs: Use the CRUD APIs to create connections programmatically through the Descope Management API or SDKs.
  3. From a DCR Preset Connection: Create a new connection instance from a DCR preset connection. This is useful when building an MCP gateway, or when you want to create different tenant-specific connections for an OAuth provider used with another MCP server.

Creating an connection in Descope

There are two different types of Connections in Descope: OAuth-based and API key-based Connections.

OAuth Connections

An OAuth Connection lets Descope run a provider's OAuth flow and store the tokens it returns. You can build one from scratch as a custom connection, or start from a pre-configured template in the library.

Register an OAuth App with the Provider

Most setups use Manual connection settings, so you register an OAuth application with the provider yourself (Google, Microsoft, Salesforce, and so on) before you configure anything in Descope. Descope then acts as a confidential OAuth client for that provider: you create the app on their side and paste its Client ID and Client Secret into Descope.

Two things need to match up on the provider's app:

  • Scopes: The app must allow the scopes you define on the Connection (see Scopes). Enable the same scopes on the provider that you list in Descope.
  • Authorized redirect URI: Whitelist Descope's outbound OAuth callback URL on the provider app (see Connection Settings below).

Some providers support Dynamic Client Registration against Descope's callback URL, which lets you skip the manual app and use the DCR option in Connection Settings instead. Most do not, so you will usually register the app by hand.

Connection Details

Note

The connection ID cannot be shared with any other connection or outbound app.

These fields set the Connection's identity and, optionally, scope it to a tenant:

  • Name (Required): Display name for the Connection.
  • Connection ID (Required): Unique identifier. Set only at creation; not editable afterward.
  • Description (Optional): Short summary of what the Connection is for.
  • Associated Tenant (Optional): Dropdown to tie the Connection to a specific tenant. Use this when the Connection should be scoped to one organization (for example, tenant-specific credentials in a gateway). Leave unset for a project-wide Connection.

Configuring an oauth connection's details in Descope

Account Information

Account Information is where you connect Descope to the provider and list the OAuth scopes the Connection can request.

Connection Settings

Choose how Descope registers as an OAuth client with the provider:

Manual

Enter credentials from an OAuth app you created at the provider:

  • Client ID (Required): The client ID from your OAuth application at the provider.
  • Client Secret (Required): The client secret from the same OAuth application.

Configuring an outbound app's connection settings in Descope

Note

Most OAuth providers require this callback URL in the app's authorized redirect URI list. Without it, the provider rejects the request when a user connects.

When creating an OAuth app integration with your desired provider, the default callback URL to whitelist is:

https://api.descope.com/v1/outbound/oauth/callback

Callback URL for app registration on a Connection

Note

If you set a Callback Domain or use a custom domain, the URL in the console may differ.

Always use the value displayed here when registering the app at the provider.

Dynamic Client Registration

If you don't wish to create an OAuth app in the provider, and the provider supports Dynamic Client Registration, you can provide a provider endpoint and Descope will register an OAuth app for you:

  • Registration URL: An /mcp URL or other dynamic client registration endpoint exposed by the provider.

Note

Most OAuth providers do not allow Dynamic Client Registration when Descope is the redirect URL.

In practice you usually need Manual registration: create an approved app at the provider, then paste its Client ID and Client Secret into Descope.

Configuring a connection with Dynamic Client Registration

Scopes

This is the master list of OAuth scopes the Connection can request from the provider. Add every scope you might need, even if you do not use them all on every connect.

Descope uses this list in a few places:

  • Default at connect time: If the MCP client, your app, or a Connection flow action does not pass specific scopes, Descope requests the scopes defined here.
  • Override at connect time: A client or flow action can request a subset (or custom set). Those override the defaults for that connect only.
  • MCP Server mapping: Scopes defined here appear in MCP Server Scopes under Connection scopes, where you map each MCP server scope to the provider scopes this Connection should fetch. They do not appear in that mapping UI until you define them on the Connection.

You must also enable the same scopes on the provider's OAuth app. Otherwise the provider will not grant them.

For example, Google Contacts defaults to full access (https://www.googleapis.com/auth/contacts), but you can configure read-only access (https://www.googleapis.com/auth/contacts.readonly) instead:

Configuring an outbound app's scopes in Descope

Note

You must also configure the same scopes in your OAuth provider's application settings (e.g., Google Cloud Console) for them to be available.

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

Additional Settings

Additional Settings covers where users land after a successful connection, which OAuth endpoints Descope calls, and optional query parameters on the authorize request.

Note

When using a predefined connection from the connections library, the authorization and token endpoints are prepopulated.

  • 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.
  • Authorize request params: Use + Add request param to attach extra query parameters to the provider's /authorize request when a user connects. Set fixed key/value pairs for provider-specific parameters such as resource, audience, or other OAuth query params this Connection always needs on the initial connect.

Configuring an outbound app's additional settings in Descope

Once created, you can read how you can connect to your OAuth provider, and fetch the OAuth tokens with our SDKs.

API Key Connections

This is ideal for integrating with external services that do not support OAuth, and use static tokens instead for authentication.

In addition to storing OAuth tokens, Descope can also store static API keys with API Key-based Connections.

A few templates use API keys, such as Jenkins and OpenAI, or you can create your own Custom API key Connection.

Connection Details

Note

The connection ID cannot be shared with any other connection.

These fields configure the connection:

  • Logo (Optional): Upload a logo by clicking the edit button on the logo. The "Connect To" consent button in your flows uses this logo automatically.
  • Connection Name (Required): The display name for the connection. You can edit it later.
  • Description (Optional): An optional description of the connection. You can edit it later.
  • Connection ID (Required): Set this only when you create the connection. It cannot be changed afterward.

Configuring an api key connection's details in Descope

API key based connections don't have any additional settings besides the details above. Once created, you can read how you can upload static tokens (API keys) to your connection, and fetch them with our SDKs.

Managing Connections

You can create, update, delete, and load connections programmatically using a Descope SDK directly via the REST API.

Create a Connection

// Create a connection
const { id } = await descopeClient.management.outboundApplication.createApplication({
  name: 'my new connection',
  description: 'my desc',
  // ...other fields (see [Connection Schema](#connection-schema) below)
});
# Create a connection
response = descope_client.mgmt.outbound_application.create_application(
    name='my new connection',
    description='my desc',
    # ...other fields (see [Connection Schema](#connection-schema) below)
)
id = response['app']['id']
// Set up the outbound apps service
OutboundAppsService outboundAppsService = descopeClient.getManagementServices().getOutboundAppsService();

// Create a connection
OutboundAppRequest request = new OutboundAppRequest();
request.setName("my new connection");
// ...other fields (see [Connection Schema](#connection-schema) below)

OutboundAppCreateResponse response = outboundAppsService.createApplication(request);
String id = response.getId();
// Create a connection
appRequest := &descope.CreateOutboundAppRequest{
    OutboundApp: descope.OutboundApp{
        Name:        "my new connection",
        Description: "my desc",
        // ...other fields (see Connection Schema below)
    },
    ClientSecret: "your-client-secret", // optional
}

app, err := descopeClient.Management.OutboundApplication().CreateApplication(ctx, appRequest)
if err != nil {
    // Handle error
}
id := app.ID
POST /v1/mgmt/outbound/app/create
Authorization: Bearer <PROJECT_ID>:<MANAGEMENT_KEY>
Content-Type: application/json

{
  "name": "my new connection",
  "description": "my desc"
  // ...other fields (see [Connection Schema](#connection-schema) below)
}

Update a Connection

// Update a connection (overrides all fields)
await descopeClient.management.outboundApplication.updateApplication({
  id: 'my-connection-id',
  name: 'my updated connection',
  // ...other fields (see [Connection Schema](#connection-schema))
});
# Update a connection (overrides all fields)
descope_client.mgmt.outbound_application.update_application(
    id='my-connection-id',
    name='my updated connection',
    # ...other fields (see [Connection Schema](#connection-schema))
)
// Update a connection (overrides all fields)
OutboundAppRequest request = new OutboundAppRequest();
request.setId("my-connection-id");
request.setName("my updated connection");
// ...other fields (see [Connection Schema](#connection-schema))

outboundAppsService.updateApplication(request);
// Update a connection (overrides all fields)
app := &descope.OutboundApp{
    ID:   "my-connection-id",
    Name: "my updated connection",
    // ...other fields (see Connection Schema)
}

clientSecret := "your-client-secret" // optional, can be nil
app, err := descopeClient.Management.OutboundApplication().UpdateApplication(ctx, app, &clientSecret)
if err != nil {
    // Handle error
}
POST /v1/mgmt/outbound/app/update
Authorization: Bearer <PROJECT_ID>:<MANAGEMENT_KEY>
Content-Type: application/json

{
  "app": {
    "id": "my-connection-id",
    "name": "my updated connection"
    // ...other fields (see [Connection Schema](#connection-schema))
  }
}

Delete a Connection

// Delete a connection by id
await descopeClient.management.outboundApplication.deleteApplication('my-connection-id');
# Delete a connection by id
descope_client.mgmt.outbound_application.delete_application(
    id='my-connection-id'
)
// Delete a connection by id
outboundAppsService.deleteApplication("my-connection-id");
// Delete a connection by id
err := descopeClient.Management.OutboundApplication().DeleteApplication(ctx, "my-connection-id")
if err != nil {
    // Handle error
}
POST /v1/mgmt/outbound/app/delete
Authorization: Bearer <PROJECT_ID>:<MANAGEMENT_KEY>
Content-Type: application/json

{
  "id": "my-connection-id"
}

Load a Connection

// Load a connection by id
const connection = await descopeClient.management.outboundApplication.loadApplication('my-connection-id');
# Load a connection by id
connection = descope_client.mgmt.outbound_application.load_application(
    id='my-connection-id'
)
// Load a connection by id
OutboundApp connection = outboundAppsService.loadApplication("my-connection-id");
// Load a connection by id
connection, err := descopeClient.Management.OutboundApplication().LoadApplication(ctx, "my-connection-id")
if err != nil {
    // Handle error
}
GET /v1/mgmt/outbound/app/{id}
Authorization: Bearer <PROJECT_ID>:<MANAGEMENT_KEY>

Load All Connections

// Load all connections
const connectionsRes = await descopeClient.management.outboundApplication.loadAllApplications();
connectionsRes.data.forEach((connection) => {
  // do something
});
# Load all connections
connections_res = descope_client.mgmt.outbound_application.load_all_applications()
for connection in connections_res['apps']:
    # do something
    pass
// Load all connections
OutboundApp[] connections = outboundAppsService.loadAllApplications();
for (OutboundApp connection : connections) {
    // do something
}
// Load all connections
connections, err := descopeClient.Management.OutboundApplication().LoadAllApplications(ctx)
if err != nil {
    // Handle error
}
for _, connection := range connections {
    // do something
}
GET /v1/mgmt/outbound/apps
Authorization: Bearer <PROJECT_ID>:<MANAGEMENT_KEY>

Connection Schema

When creating or updating a connection, you can configure the following fields:

Connection Fields

FieldTypeRequiredDescription
idstringOptional (create)Unique identifier for the connection. Auto-generated if not provided during creation.
namestringRequiredDisplay name for the connection.
descriptionstringOptionalHuman-readable description of the connection.
logostringOptionalURL or path to the connection logo.
clientIdstringOptionalOAuth client ID from the provider. Required for OAuth connections.
clientSecretstringOptionalOAuth client secret from the provider. Required for OAuth connections.
discoveryUrlstringOptionalOAuth discovery URL for automatic endpoint configuration.
authorizationUrlstringOptionalOAuth authorization endpoint URL. Required if discoveryUrl is not provided.
authorizationUrlParamsarrayOptionalAdditional parameters to include in authorization requests.
tokenUrlstringOptionalOAuth token endpoint URL. Required if discoveryUrl is not provided.
tokenUrlParamsarrayOptionalAdditional parameters to include in token exchange requests.
revocationUrlstringOptionalOAuth token revocation endpoint URL.
defaultScopesarray of stringsOptionalDefault OAuth scopes to request for all connections.
defaultRedirectUrlstringOptionalDefault redirect URL after successful OAuth flow.
callbackDomainstringOptionalDomain to use for OAuth callbacks. Defaults to project domain.
pkcebooleanOptionalEnable PKCE (Proof Key for Code Exchange) for OAuth flows.
accessTypestringOptionalOAuth access type (e.g., "offline" for refresh tokens).
promptarray of stringsOptionalOAuth prompt parameters (e.g., ["consent", "select_account"]).
appTypestringOptionalType of application. Will always be "custom" for manually created connections.

URL Parameter Structure

The authorizationUrlParams and tokenUrlParams fields accept an array of URL parameter objects with the following structure:

FieldTypeRequiredDescription
keystringRequiredThe parameter name.
valuestringRequiredThe parameter value.

Here's an example of a complete connection object with all available fields:

const connection = {
  name: 'Google Contacts',
  description: 'Access Google Contacts API',
  logo: 'https://example.com/logo.png',
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
  tokenUrl: 'https://oauth2.googleapis.com/token',
  defaultScopes: ['https://www.googleapis.com/auth/contacts.readonly'],
  defaultRedirectUrl: 'https://app.example.com/callback',
  callbackDomain: 'app.example.com',
  pkce: true,
  accessType: 'offline',
  prompt: ['consent']
};
connection = {
    'name': 'Google Contacts',
    'description': 'Access Google Contacts API',
    'logo': 'https://example.com/logo.png',
    'client_id': 'your-client-id',
    'client_secret': 'your-client-secret',
    'authorization_url': 'https://accounts.google.com/o/oauth2/v2/auth',
    'token_url': 'https://oauth2.googleapis.com/token',
    'default_scopes': ['https://www.googleapis.com/auth/contacts.readonly'],
    'default_redirect_url': 'https://app.example.com/callback',
    'callback_domain': 'app.example.com',
    'pkce': True,
    'access_type': 'offline',
    'prompt': ['consent']
}
OutboundAppRequest request = new OutboundAppRequest();
request.setName("Google Contacts");
request.setDescription("Access Google Contacts API");
request.setLogo("https://example.com/logo.png");
request.setClientId("your-client-id");
request.setClientSecret("your-client-secret");
request.setAuthorizationUrl("https://accounts.google.com/o/oauth2/v2/auth");
request.setTokenUrl("https://oauth2.googleapis.com/token");
request.setDefaultScopes(Arrays.asList("https://www.googleapis.com/auth/contacts.readonly"));
request.setDefaultRedirectUrl("https://app.example.com/callback");
request.setCallbackDomain("app.example.com");
request.setPkce(true);
request.setAccessType("offline");
request.setPrompt(Arrays.asList("consent"));
app := &descope.OutboundApp{
    Name:        "Google Contacts",
    Description: "Access Google Contacts API",
    Logo:        "https://example.com/logo.png",
    ClientID:     "your-client-id",
    AuthorizationURL: "https://accounts.google.com/o/oauth2/v2/auth",
    TokenURL:     "https://oauth2.googleapis.com/token",
    DefaultScopes: []string{"https://www.googleapis.com/auth/contacts.readonly"},
    DefaultRedirectURL: "https://app.example.com/callback",
    CallbackDomain: "app.example.com",
    Pkce:        true,
    AccessType:  "offline",
    Prompt:      []string{"consent"},
}

appRequest := &descope.CreateOutboundAppRequest{
    OutboundApp:  *app,
    ClientSecret: "your-client-secret",
}
{
  "name": "Google Contacts",
  "description": "Access Google Contacts API",
  "logo": "https://example.com/logo.png",
  "clientId": "your-client-id",
  "clientSecret": "your-client-secret",
  "authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth",
  "authorizationUrlParams": [
    {
      "key": "hd",
      "value": "example.com"
    }
  ],
  "tokenUrl": "https://oauth2.googleapis.com/token",
  "tokenUrlParams": [],
  "defaultScopes": ["https://www.googleapis.com/auth/contacts.readonly"],
  "defaultRedirectUrl": "https://app.example.com/callback",
  "callbackDomain": "app.example.com",
  "pkce": true,
  "accessType": "offline",
  "prompt": ["consent"],
  "appType": "custom"
}

For more information on how to store tokens and connect to your Connection, see the Storing Connection Tokens documentation.

For more information on how to fetch these tokens see this doc.

Was this helpful?

On this page