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

# Custom domain

> Configure Stytch to use your custom domain.

## **Why domains matter in OAuth**

In OAuth and OpenID Connect (OIDC), many core features rely on a single authoritative domain.

The most important of these is the **issuer** — a required field in Access and ID token JWTs that uniquely identifies your Stytch application as the entity that created the token. Consumers of these JWTs use the issuer during validation to ensure the token's authenticity.

Another key feature is the set of **well-known metadata URLs**, which OAuth clients use to automatically discover server configuration. These endpoints expose metadata about available capabilities and supported flows.

* For OAuth: `https://<domain>/.well-known/oauth-authorization-server`
* For OIDC: `https://<domain>/.well-known/openid-configuration`

Stytch will automatically provision a default domain for your project upon creation. Default domains are intended for convenient testing of an initial integration. However, this domain is frequently shared with external consumers of your application. We recommend setting up a [Branded Custom Domain](/resources/branding/custom-domains) as a subdomain of your main website before going live with your integration.

## **Configuring Stytch SDKs to use your domain**

Stytch SDKs must be configured to use the correct domain for your project.

For B2B applications:

<CodeGroup>
  ```javascript Node SDK theme={null}
  const client = new stytch.B2BClient({
    project_id: "PROJECT_ID",
    secret: "SECRET",
    custom_base_url: "${projectDomain}",
  });
  ```

  ```python Python SDK theme={null}
  client = B2BClient(
    project_id="PROJECT_ID",
    secret="SECRET",
    custom_base_url="${projectDomain}",
  )
  ```

  ```ruby Ruby SDK theme={null}
  client = StytchB2B::Client.new(
    project_id: "PROJECT_ID",
    secret: "SECRET"
    env: "${projectDomain}",
  )
  ```

  ```go Go SDK theme={null}
  stytchClient, err := b2bstytchapi.NewClient(
      "PROJECT_ID",
      "SECRET",
      b2bstytchapi.WithBaseURI("${projectDomain}")
  )
  ```

  ```javascript Frontend Javascript SDK theme={null}
  const client = createStytchB2BClient(
    "PUBLIC_TOKEN",
    {
      customBaseUrl: "${projectDomain}",
    }
  );
  ```
</CodeGroup>

For Consumer applications:

<CodeGroup>
  ```javascript Node SDK theme={null}
  const client = new stytch.Client({
    project_id: "PROJECT_ID",
    secret: "SECRET",
    custom_base_url: "${projectDomain}",
  });
  ```

  ```python Python SDK theme={null}
  client = Client(
    project_id="PROJECT_ID",
    secret="SECRET",
    custom_base_url="${projectDomain}",
  )
  ```

  ```ruby Ruby SDK theme={null}
  client = Stytch::Client.new(
    project_id: "PROJECT_ID",
    secret: "SECRET"
    env: "${projectDomain}",
  )
  ```

  ```go Go SDK theme={null}
  stytchClient, err := stytchapi.NewClient(
      "PROJECT_ID",
      "SECRET",
      stytchapi.WithBaseURI("${projectDomain}")
  )
  ```

  ```javascript Frontend Javascript SDK theme={null}
  const client = createStytchClient(
    "PUBLIC_TOKEN",
    {
      customBaseUrl: "${projectDomain}",
    }
  );
  ```
</CodeGroup>

## **How Custom Domains affect Connected Apps**

Stytch will dynamically determine JWT issuers and well-known URL responses based on the domain used to access the Stytch service.

### **Using the default project domain**

All Stytch projects are provisioned a unique default domain upon creation.

* In `test` environments, the domain will look like `https://{noun}-{verb}-{number}.customers.stytch.dev`.
* In `live` environments, the domain will look like `https://{noun}-{verb}-{number}.customers.stytch.dev`.

API calls occurring over this domain will use the domain value while processing the request.

For example, the Access token and ID token returned from this Exchange Authorization Code (for [B2B](/api-reference/b2b/api/connected-apps/exchange-authorization-code), for [Consumer](/api-reference/consumer/api/connected-apps/exchange-authorization-code)) call will have an `issuer` of `https://{noun}-{verb}-{number}.customers.stytch.dev`.

```bash theme={null}
curl -X POST https://{noun}-{verb}-{number}.customers.stytch.dev/oauth2/token \
	-H 'Content-Type: application/json' \
	-d '{
		"client_id": "connected-app-test-d731954d-dab3-4a2b-bdee-07f3ad1be888",
		"client_secret": "NHQhc7ZqsXJVtgmN2MXr1etqsQrGAwJ-iBWNLKY7DzJq",
		"redirect_uri": "https://example.com/callback",
		"grant_type": "authorization_code",
		"code": "PvC5UudZ7TPZbELt95yXAQ-8MeEUCRob8bUQ-g52fIJs"
	}'
# => { "access_token": "eyJ...", "id_token": "eyJ...", ... }
```

Similarly, the metadata returned from this Get OpenID Configuration (for [B2B](/api-reference/b2b/api/connected-apps/configuration/get-openid-configuration), for [Consumer](/api-reference/consumer/api/connected-apps/configuration/get-openid-configuration)) call will use the `https://{noun}-{verb}-{number}.customers.stytch.dev`:

```bash theme={null}
curl --request GET \
	--url https://{noun}-{verb}-{number}.customers.stytch.dev/.well-known/openid-configuration
```

like so:

```bash theme={null}
{
  "registration_endpoint": "https://{noun}-{verb}-{number}.customers.stytch.dev/v1/oauth2/register",
  "token_endpoint": "https://{noun}-{verb}-{number}.customers.stytch.dev/v1/oauth2/token",
  "userinfo_endpoint": "https://{noun}-{verb}-{number}.customers.stytch.dev/v1/oauth2/userinfo",
  ...
}
```

### **Using a branded custom domain (CNAME)**

When you configure a custom domain (e.g. `https://login.yourcompany.com`) and make API calls using that domain, Stytch will use that domain instead.

The Access token and ID token returned from this call will have an `issuer` of `https://login.yourcompany.com`.

```bash theme={null}
curl -X POST https://login.yourcompany.com/oauth2/token \
	-H 'Content-Type: application/json' \
	-d '{
		"client_id": "connected-app-test-d731954d-dab3-4a2b-bdee-07f3ad1be888",
		"client_secret": "NHQhc7ZqsXJVtgmN2MXr1etqsQrGAwJ-iBWNLKY7DzJq",
		"redirect_uri": "https://example.com/callback",
		"grant_type": "authorization_code",
		"code": "PvC5UudZ7TPZbELt95yXAQ-8MeEUCRob8bUQ-g52fIJs"
	}'
# => { "access_token": "eyJ...", "id_token": "eyJ...", ... }
```

Similarly, the metadata returned from this call will use the `https://login.yourcompany.com` domain:

```bash theme={null}
curl --request GET \
	--url https://login.yourcompany.com/.well-known/openid-configuration
```

like so:

```bash theme={null}
{
  "registration_endpoint": "https://login.yourcompany.com/v1/oauth2/register",
  "token_endpoint": "https://login.yourcompany.com/v1/oauth2/token",
  "userinfo_endpoint": "https://login.yourcompany.com/v1/oauth2/userinfo",
  ...
}
```

## Migrating from **api.stytch.com**

If you were an early customer of Connected Apps, you may be accessing the product over `api.stytch.com` - e.g. `https://api.stytch.com/v1/public/${projectId}/oauth2/token`. When accessed this way, Stytch will use the project ID (`stytch.com/$projectId`) as the issuer. These issuers are not [OpenID Connect (OIDC)](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) compliant, as they are not HTTPS URLs.

### **Why does this matter?**

* Many OIDC clients and libraries will reject tokens if the `issuer` does not match the expected `https` URL.
* Using a custom domain ensures maximum compatibility and security for your integrations.

### **To get a fully OIDC-compliant issuer:**

1. [Set up a custom domain (CNAME)](/resources/branding/custom-domains) in your DNS that points to Stytch and configure Stytch to recognize this domain.
2. [Configure your application](#Configuring-Stytch-SDKs-to-use-your-domain) to make all API calls to Stytch over this domain.
3. Use this domain for all authentication flows.

All Stytch backend SDKs will accept both the old and new format issuers when performing JWT validation to ensure a seamless transition.
