Managing Environments

Descope allows you to create many projects to fit your needs. You could have multiple projects for different businesses, or you could have a development, staging, and production projects for the various stages of your development and testing. Descope makes it easy to manage your projects and migrate configurations between projects.

Creating Projects

Within the Descope console, clicking the project drop down in the top right allows you to create new projects by clicking the + Project button at the bottom of the list of your projects. When you create a new project, you can provide the project with a name and choose whether it is production or non-production. You can later change whether the project is production or non-production from the Project Settings page within the console. Note that selecting production or non-production does not effect the features within the project. This is an internal identifier for Descope to see which projects are marked as production.

Creating a new project within Descope.

Managing Secrets in Environments

When working with environments, it's essential to note Descope's behavior in handling API keys and other related secrets around connectors and OAuth provider configurations. The below outlines how Descope manages secrets and credentials during project cloning, exporting, and importing.

  • During the cloning of a project, secrets are cloned to the new project with all of their current configuration and settings.
  • While exporting a project, the exported project zip will contain the connector or OAuth provider configuration; however, the credentials will be removed to prevent the export of secrets.
  • It is possible to import connectors and OAuth providers with their credentials and secrets when importing a project. The examples below outline how you would import connectors with secrets, but the same applies to OAuth providers.
  • If you have exported a project and are importing that project to another project that already has the same connectors or OAuth providers configured, the secrets stored within the project you are importing to will be retained (unless overridden by editing the secrets within the exported zip), but the other settings of the connector or OAuth provider will be updated. Please also see the documentation around secret placeholders for more information on overriding secrets.

Importing Secrets

When you export your project, you will receive a zip file with the contents, such as the one below.

project-xxx
├── assets
│		 ├── assets.json
│		 ├── body-xxx.html
...
├── attributes.json
├── auth
│		 ├── embeddedlink.json
│		 ├── enchantedlink.json
...
├── connectors
│		 ├── connectors.json
│		 ├── http-xxx.json
│		 ├── smtp-xxx.json
│		 └── twilio-xxx.json
├── environment.json
├── flows
│		 ├── sign-up-or-in
│		 │		 ├── flow.json
│		 │		 ├── screen-1.json
...
├── project.json
├── ssoapps.json
└── styles
    ├── dark.json
    ├── light.json
    └── styles.json

The connectors directory includes the configuration of each connector associated your Project.

HTTPSMTPTwilio
{
  "configuration": {
    "authentication": {
      "apiKey": {},
      "basic": {},
      "method": "bearerToken"
    },
    "baseUrl": "https://api.sendgrid.com/v3/mail",
    "headers": [
      {
        "key": "Content-Type",
        "value": "application/json"
      }
    ],
    "insecure": false
  },
  "contentVersion": "",
  "description": "Sendgrid Generic HTTP",
  "id": "xxxx",
  "name": "Sendgrid Generic",
  "status": "enabled",
  "templateId": "http"
}
{
  "authMethod": "",
  "common": {
    "description": "MS SMTP",
    "displayName": "MS SMTP",
    "id": "xxxx"
  },
  "fromEmail": "user@email.com",
  "fromName": "User",
  "host": "smtp.office365.com",
  "password": "",
  "port": 587,
  "username": "user@email.com"
}
{
  "accountSid": "xxxxx",
  "apiKey": "",
  "apiSecret": "",
  "authToken": "",
  "common": {
    "description": "",
    "displayName": "My Twillio",
    "id": "xxxxx"
  },
  "fromPhone": "xxxxx",
  "messagingServiceSid": "xxxx",
  "selectedAuthProp": "methodAuthToken",
  "selectedProp": "messagingServiceSid"
}

To import the secrets within a new project, add them to the downloaded files within the zip, zip the entire directory back up, and then import them to your new project. This will then import the secrets into your project and allow the connectors to be immediately used without further configuration of the connectors after the import.

Secret Placeholders

When you export a project with connectors or OAuth providers configured with secrets, you will see that the secrets will have a placeholder of PLACEHOLDER_VALUE. There are two options when handling placeholders within the secrets of the configuration files.
  • If you leave PLACEHOLDER_VALUE in the exported configuration file, the secrets in the project you are importing will be retained.
  • If you would like to override the configured secrets within the project, you would change the PLACEHOLDER_VALUE to be the correct secrets for the project.
  • Removing the line containing the placeholder or replacing "PLACEHOLDER_VALUE" with null or "" will clear the configured value from the secret on import.
Below are examples of connector and OAuth provider configurations with PLACEHOLDER_VALUE.

HTTP ConnectorOAuth Provider Configuration
{
  "configuration": {
    "authentication": {
      "apiKey": {},
      "basic": {},
      "bearerToken": "PLACEHOLDER_VALUE",
      "method": "bearerToken"
    },
    "baseUrl": "https://example.com",
    "hmacSecret": "PLACEHOLDER_VALUE",
    "hmacSignEntireRequest": true,
    "includeHeadersInContext": true,
    "insecure": false
  },
  "contentVersion": "",
  "description": "",
  "id": "xxxxx",
  "name": "Example Connector",
  "status": "enabled",
  "templateId": "http"
}
{
      "Spotify": {
      "authUrl": "https://accounts.spotify.com/authorize",
      "callbackDomain": "",
      "clientId": "xxxxx",
      "clientSecret": "PLACEHOLDER_VALUE",
      "custom": true,
      "defaultScopes": [],
      "description": "",
      "enabled": true,
      "grantType": "authorization_code",
      "issuer": "",
      "jwksUrl": "",
      "logo": "asset:img-xxxxx.png",
      "manageProviderTokens": true,
      "name": "Spotify",
      "prompts": [],
      "redirectUrl": "",
      "responseMode": "",
      "revokeUrl": "",
      "scopeDelimiter": "%20",
      "scopes": [
        "user-read-email"
      ],
      "signAlgorithm": "RS256",
      "tokenUrl": "https://accounts.spotify.com/api/token",
      "trustProvidedEmails": true,
      "useNonce": false,
      "useSelfAccount": true,
      "userDataAuthHeaderName": "Authorization",
      "userDataAuthHeaderType": "Bearer",
      "userDataAuthQueryParamName": "",
      "userDataClaimsMapping": {
        "email": "email",
        "familyName": "",
        "givenName": "",
        "loginId": "email",
        "middleName": "",
        "name": "display_name",
        "phoneNumber": "",
        "picture": "",
        "username": "",
        "verifiedEmail": "",
        "verifiedPhone": ""
      },
      "userDataHeaders": {},
      "userDataQueryParams": {},
      "userDataUrl": "https://api.spotify.com/v1/me"
    }
}

Cloning Projects

From the Project Settings page Descope allows you to clone your projects. This allows you to create a duplicate of your current project. A use case for this would be cloning your development project to create a staging and production project. This will copy your flows, styles, project settings, authentication method configurations, email templates, etc.

Cloning a project within Descope.

Exporting Projects

Within Descope, you can export a project from the Project Settings page. This exports your flows, styles, project settings, authentication method configurations, email templates, etc. You can then import the downloaded zip file into another project, or selectively import your flows or styles into another project.

Cloning a project within Descope.

Importing Projects

Descope allows you to import an exported project to another existing project. This is useful when you are working between development, staging, and production projects. Once you have tested your configurations within your environments, you can export and import the project into the next level in your deployments.

Cloning a project within Descope.

Partial Project Importing

When migrating a project from one environment to another, it's important to ensure that only the necessary components are transferred, allowing for a seamless integration without overwriting critical configurations in the new project. This document outlines how you can selectively remove specific folders or files within the exported project folder. By doing so, you prevent these items from being imported into the new project, ensuring that the specific values aren't overwritten.

To exclude specific elements during the import process, you should:

  1. Export your project: Begin by exporting the entire project from your current environment. This is documented here.
  2. Modify the export: Before importing, remove or edit the project.json file to exclude specific keys. Additionally, delete any files or folders that you do not wish to import.
  3. Import the modified project: Once you have customized your project export by removing unwanted elements, import the project into your new environment.

Note: You can also use the Descope API import endpoint with the excludes argument with the documented flags to exclude certain items from an export as well.

Customizable Elements in project.json

The project.json file contains several keys that you can choose not to include in your import. Removing or altering these keys from project.json before importing ensures that the corresponding settings in your new project remain unchanged:
  • domain
  • trustedDomains
  • tokenResponseMethod
  • selfProvisioning
  • rotateJwt
  • cookiepolicy
  • refreshTokenExpiration
  • stepupTokenExpiration
  • sessionTokenExpiration
  • keySessionTokenExpiration
  • inviteUrl
  • inviteEmail
  • inviteSms
  • inviteMagicLink
  • conformanceJwt
  • inactivity
An example of the project.json file looks like this:
{
  "conformanceJwt": false,
  "cookiePolicy": 3,
  "domain": "",
  ...
}

Non-Modifiable Files and Folders

Aside from the specific keys in project.json, there are various files and folders that you can choose to include or exclude entirely from your import. However, it's important to note that individual elements within these files cannot be modified from their original export. Here’s what you can choose to exclude:
  1. All JSON files under the auth directory control different authentication mechanisms. You have the option to include or exclude these files as a whole:
  • auth/magicLink.json
  • auth/enchantedLink.json
  • auth/embeddedLink.json
  • auth/otp.json
  • auth/totp.json
  • auth/sso.json
  • auth/oauth.json
  • auth/webauthn.json
  • auth/password.json
  1. The following directories and files are crucial to the project's functionality but can be selectively included or excluded based on your requirements:
  • styles folder
  • flows folder
  • connectors folder
  • roles.json
  • ssoApps.json

Any file or folder not listed above, should not be altered, as that could affect the success of the project import.

Conclusion

Customizing your project import allows you to maintain the integrity of your new project's configuration, preventing unintended overwrites and ensuring a smooth transition. Carefully review and modify the exported project files and folders according to the guidelines provided to achieve the desired outcome in your new project environment.

Tracking Changes

If you would like to track changes between your project configurations, you can export your project and store within your code repository of choice. This allows you to track the configuration changes you have made within your projects over time.

Descope also offers a GitHub template with built in GitHub actions which enable you to quickly configure your CI/CD pipeline within GitHub. You can review this tool within our Knowledge Base Article.

Managing Projects from the Management SDK

The Descope SDK allows you clone projects. This requires a pro or enterprise tier licenses.

Install SDK

NodeJSPythonGoJavaRuby
npm i --save @descope/node-sdk
pip3 install descope
go get github.com/descope/go-sdk
// Include the following in your `pom.xml` (for Maven)
<dependency>
    <artifactId>java-sdk</artifactId>
    <groupId>com.descope</groupId>
    <version>sdk-version</version> // Check https://github.com/descope/descope-java/releases for the latest versions
</dependency>
gem install descope

Import and initialize Management SDK

NodeJSPythonGoJavaRuby
import DescopeClient from '@descope/node-sdk';

const managementKey = "xxxx"

try{
    //  baseUrl="<URL>" // When initializing the Descope clientyou can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize CNAME within your Descope project.
    const descopeClient = DescopeClient({ projectId: '__ProjectID__', managementKey: managementKey });
} catch (error) {
    // handle the error
    console.log("failed to initialize: " + error)
}

// Note that you can handle async operation failures and capture specific errors to customize errors.
//     An example can be found here: https://github.com/descope/node-sdk?tab=readme-ov-file#error-handling
from descope import (
    REFRESH_SESSION_TOKEN_NAME,
    SESSION_TOKEN_NAME,
    AuthException,
    DeliveryMethod,
    DescopeClient,
    AssociatedTenant,
    RoleMapping,
    AttributeMapping
)

management_key = "xxxx"

try:
    # You can configure the baseURL by setting the env variable Ex: export DESCOPE_BASE_URI="https://auth.company.com  - this is useful when you utilize CNAME within your Descope project."
    descope_client = DescopeClient(project_id='__ProjectID__', management_key=management_key)
except Exception as error:
    # handle the error
    print ("failed to initialize. Error:")
    print (error)
import "github.com/descope/go-sdk/descope"
import "github.com/descope/go-sdk/descope/client"
import "fmt"

// Utilizing the context package allows for the transmission of context capabilities like cancellation
//      signals during the function call. In cases where context is absent, the context.Background()
//      function serves as a viable alternative.
//      Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
import (
	"context"
)

managementKey = "xxxx"

// DescopeBaseURL // within the client.Config, you can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize CNAME within your Descope project.
descopeClient, err := client.NewWithConfig(&client.Config{ProjectID:"__ProjectID__", managementKey:managementKey})
if err != nil {
    // handle the error
    log.Println("failed to initialize: " + err.Error())
}
import com.descope.client;

// Initialized after setting the DESCOPE_PROJECT_ID env var (and optionally DESCOPE_MANAGEMENT_KEY)
var descopeClient = new DescopeClient();

// ** Or directly **
var descopeClient = new DescopeClient(Config.builder()
        .projectId("__ProjectID__")
        .managementKey("management-key")
        .build());
require 'descope'


descope_client = Descope::Client.new(
  {
    project_id: '__ProjectID__',
    management_key: 'management_key'
  }
)

Update Project Name

This endpoint allows you to update the current project's name.

NodeJSPythonGoJava
// Args
//   name (str): The new name for the project.
const name = "New Project Name"

const resp = await descopeClient.management.project.updateName(name)
if (!resp.ok) {
  console.log(resp)
  console.log("Failed to update project name.")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully updated project name.")
}
# Args
#   name (str): The new name for the project.
name = "New Project Name"

try:
  resp = descope_client.mgmt.project.update_name(name=name)
  print ("Successfully updated project name.")
except AuthException as error:
  print ("Failed to update project name.")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
// Args
//   ctx: context.Context - Application context for the transmission of context capabilities like
//        cancellation signals during the function call. In cases where context is absent, the context.Background()
//        function serves as a viable alternative.
//        Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()
//   name (str): The new name for the project.
name := "New Project Name"

err := descopeClient.Management.Project().UpdateName(name, nil)
if err != nil {
  fmt.Print("Failed to update project name.", err)
} else {
  fmt.Println("Successfully updated project name.")
}
ProjectService ps = descopeClient.getManagementServices().getProjectService();

try {
    ps.updateName("New Project Name");
} catch (DescopeException de) {
    // Handle the error
}

Export Project

This endpoint allows you to export the current project.

NodeJSPythonGoJava
// Args
//   None

const resp = await descopeClient.management.project.export()
if (!resp.ok) {
  console.log(resp)
  console.log("Failed to export project.")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully exported project.")
  console.log(resp.data)
}
# Args
#   None

try:
  resp = descope_client.mgmt.project.export_project()
  print ("Successfully exported project")
  print (resp)
except AuthException as error:
  print ("Failed to export project")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
// Args
//   ctx: context.Context - Application context for the transmission of context capabilities like
//        cancellation signals during the function call. In cases where context is absent, the context.Background()
//        function serves as a viable alternative.
//        Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()

res, err := descopeClient.Management.Project().Export(ctx)
if err != nil {
  fmt.Print("Failed to export project", err)
} else {
  fmt.Println("Successfully exported project", res)
}
ProjectService ps = descopeClient.getManagementServices().getProjectService();

try {
    ExportProjectResponse resp = ps.exportProject();
} catch (DescopeException de) {
    // Handle the error
}

Import Project

This endpoint allows you to import all settings and configurations into the current project. Use with caution, this endpoint overrides any current configuration.

NodeJSPythonGoJava
// Args
//   files (<Record<string, any>): The raw JSON dictionary of files, in the same format as the one returned by calls to export.
const files = {
                  "files": {
                ...
                }
              }

const resp = await descopeClient.management.project.import(files)
if (!resp.ok) {
  console.log(resp)
  console.log("Failed to import project.")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully imported project.")
}
# Args
#   files (dict): The raw JSON dictionary of files, in the same format as the one returned by calls to export.
files = {
          "files": {
        ...
        }
      }

try:
  resp = descope_client.mgmt.project.import_project(name=name)
  print ("Successfully imported project")
except AuthException as error:
  print ("Failed to import project")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
// Args
//   ctx: context.Context - Application context for the transmission of context capabilities like
//        cancellation signals during the function call. In cases where context is absent, the context.Background()
//        function serves as a viable alternative.
//        Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()
//   req (ImportProjectRequest): The raw JSON dictionary of files, in the same format as the one returned by calls to export.
req = := &descope.ImportProjectRequest{}
req.Files map[string]any{
          "files": {
        ...
        }
      }

err := descopeClient.Management.Project().Import(req)
if err != nil {
  fmt.Print("Failed to import project", err)
} else {
  fmt.Println("Successfully imported project")
}
ProjectService ps = descopeClient.getManagementServices().getProjectService();

try {
    ps.importProject({
          "files": {
        ...
        }
      });
} catch (DescopeException de) {
    // Handle the error
}

Clone Project

This function allows you to clone the current project, including its settings and configurations.

Note: Users, tenants and access keys are not cloned.

NodeJSPythonGoJava
// Args
//   name (str): The new name for the project.
const name = "New Project"
//   tag(str): Optional tag for the project. Currently, only the "production" tag is supported.

const resp = await descopeClient.management.project.clone(name, null)
if (!resp.ok) {
  console.log(resp)
  console.log("Failed to clone project.")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully cloned project.")
  console.log(resp.data)
}
# Args
#   name (str): The new name for the project.
name = "New Project"
#   tag(str): Optional tag for the project. Currently, only the "production" tag is supported.

try:
  resp = descope_client.mgmt.project.clone(name=name)
  print ("Successfully cloned project")
  print (resp)
except AuthException as error:
  print ("Failed to clone project")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
// Args
//   ctx: context.Context - Application context for the transmission of context capabilities like
//        cancellation signals during the function call. In cases where context is absent, the context.Background()
//        function serves as a viable alternative.
//        Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()
//   name (str): The new name for the project.
name := "New Project"
//   tag(str): Optional tag for the project. Currently, only the "production" tag is supported.

res, err := descopeClient.Management.Project().Clone(ctx, name, nil)
if err != nil {
  fmt.Print("Failed to clone project", err)
} else {
  fmt.Println("Successfully cloned project", res)
}
ProjectService ps = descopeClient.getManagementServices().getProjectService();

// Clone the current project to a new one
// Note that this action is supported only with a pro license or above.
try {
    NewProjectResponse resp = ps.clone("New Project Name", ProjectTag.None);
} catch (DescopeException de) {
    // Handle the error
}