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

# Configure an Application for Universal Portals

> Configure the Regular Web Application for Universal Portals, including recommended settings, API access, and refresh tokens.

> [!WARNING]
>
> **The Auth0 Universal Portals feature is in .**

Every Portal is backed by one Auth0 [Regular Web Application](https://auth0.com/docs/get-started/auth0-overview/create-applications/regular-web-apps.md). The portal server uses the application's credentials to sign users in and to get access tokens for the [My Account API](https://auth0.com/docs/manage-users/my-account-api.md) and the [My Organization API](https://auth0.com/docs/manage-users/my-organization-api.md). An application serves one Portal, and a Portal uses one application.

The [Universal Portals Quickstart](https://auth0.com/docs/customize/portals/quickstart.md) creates and configures the Regular Web Application for you. Use this page when you want to link an existing application, manage your configuration as code, or review the settings.

```mermaid theme={null}
flowchart LR
    portal["Portal"] --- app["Regular Web Application<br/>(one per portal)"]
    app -- "Client grant and<br/>refresh token policy" --> myaccount["My Account API"]
    app -- "Client grant and<br/>refresh token policy" --> myorg["My Organization API"]
```

## Requirements by scenario

| Scenario | Requirements |
| - | - |
| Consumer Portal | Access to the My Account API with the My Account API scopes |
| Business Portal | Access to the My Organization API with the My Organization API scopes, and the [organization context](#organization-context) settings |
| Native application | The application accepts session transfer tokens. See [Native application](#native-application) |
| Forms that update users | A separate machine-to-machine application for the Forms vault. See [Forms that update users](#forms-that-update-users) |

Each resource server that your Portal calls, the My Account API and the My Organization API, needs two things:

* A client grant, which allows the application to request the scopes.
* A refresh token policy, which allows the portal server to exchange the refresh token (Refresh Token: Special kind of token that can be used to obtain a renewed Access Token. It is useful for renewing expiring Access Tokens without forcing the user to log in again.) for an access token for that resource server.

If either is missing, [components](https://auth0.com/docs/customize/portals/portal-components.md) fail with API errors. To learn more, read [Multi-Resource Refresh Token](https://auth0.com/docs/secure/tokens/refresh-tokens/multi-resource-refresh-token.md).

The scopes to grant depend on the components that your Portal uses. The following lists contain every scope that the supported components need. Remove the ones for components you do not use. To see the scopes of each component, read [Portal Components Library Reference](https://auth0.com/docs/customize/portals/portal-components.md).

> **My Account API scopes**
>
> Audience: `https://YOUR_DOMAIN/me/`
>
> * `read:me:factors`
> * `read:me:authentication_methods`
> * `create:me:authentication_methods`
> * `delete:me:authentication_methods`

> **My Organization API scopes**
>
> Audience: `https://YOUR_DOMAIN/my-org/`
>
> * `read:my_org:details`
> * `update:my_org:details`
> * `read:my_org:configuration`
> * `read:my_org:domains`
> * `create:my_org:domains`
> * `update:my_org:domains`
> * `delete:my_org:domains`
> * `read:my_org:identity_providers`
> * `create:my_org:identity_providers_domains`
> * `delete:my_org:identity_providers_domains`

## Recommended configuration

Use these settings for the portal application. The refresh token lifetimes match the portal session: 1 hour of inactivity and 1 day in total. Grant only the scopes for the components that your Portal uses, and remove the policy and the grant for a resource server that your Portal does not call.

**Auth0 Dashboard**

**1. Create the application**

Navigate to [**Auth0 Dashboard > Integration > Applications**](https://manage.auth0.com/dashboard/#/applications/list), select **Create Application**, choose **Regular Web Applications**, and enter a name.

**2. Set the URLs**

In the **Settings** tab, set **Allowed Callback URLs** to `https://YOUR_DOMAIN/portals/auth/callback`. Set **Allowed Logout URLs** to the URL of your application, which is where users land after they log out of the Portal.

**3. Trust the token endpoint IP header**

In the **Credentials** tab, under **Advanced**, enable **Trust token endpoint IP header**.

**4. Set the grant types**

In **Advanced Settings > Grant Types**, enable **Authorization Code**, **Refresh Token**, and **MFA**. Leave all other grant types off.

**5. Set the refresh token lifetimes**

In **Refresh Token Expiration**, enable **Set Idle Refresh Token Lifetime** and enter 3600 seconds. Enable **Set Maximum Refresh Token Lifetime** and enter 86400 seconds. Leave refresh token rotation off, which is the default.

**6. Allow organizations**

In the **Organizations** tab, set **Type of Users** to **Both** and **Login Flow** to **No Prompt**.

**7. Grant API access**

In the **API Access** tab, authorize the My Account API and the My Organization API for user access, with the scopes from [Requirements by scenario](#requirements-by-scenario).

**8. Enable multi-resource refresh tokens**

In **Multi-Resource Refresh Token**, enable the same APIs and scopes. Select **Save Changes**.

**Management API**

Create the application. The payload sets the values that differ from the defaults for a new Regular Web Application, and the refresh token policies for both resource servers. The API requires `rotation_type` whenever you send `refresh_token`.

```bash wrap lines theme={null}
curl --request POST \
  --url "https://YOUR_DOMAIN/api/v2/clients" \
  --header "authorization: Bearer {managementApiToken}" \
  --header "content-type: application/json" \
  --data '{
    "name": "{portalName} (Universal Portals)",
    "app_type": "regular_web",
    "oidc_conformant": true,
    "callbacks": ["https://YOUR_DOMAIN/portals/auth/callback"],
    "allowed_logout_urls": ["{yourApplicationUrl}"],
    "grant_types": [
      "authorization_code",
      "refresh_token",
      "http://auth0.com/oauth/grant-type/mfa-oob",
      "http://auth0.com/oauth/grant-type/mfa-otp",
      "http://auth0.com/oauth/grant-type/mfa-recovery-code"
    ],
    "token_endpoint_auth_method": "client_secret_post",
    "is_token_endpoint_ip_header_trusted": true,
    "organization_usage": "allow",
    "refresh_token": {
      "rotation_type": "non-rotating",
      "expiration_type": "expiring",
      "token_lifetime": 86400,
      "idle_token_lifetime": 3600,
      "policies": [
        {
          "audience": "https://YOUR_DOMAIN/me/",
          "scope": [
            "read:me:factors",
            "read:me:authentication_methods",
            "create:me:authentication_methods",
            "delete:me:authentication_methods"
          ]
        },
        {
          "audience": "https://YOUR_DOMAIN/my-org/",
          "scope": [
            "read:my_org:details",
            "update:my_org:details",
            "read:my_org:configuration",
            "read:my_org:domains",
            "create:my_org:domains",
            "update:my_org:domains",
            "delete:my_org:domains",
            "read:my_org:identity_providers",
            "create:my_org:identity_providers_domains",
            "delete:my_org:identity_providers_domains"
          ]
        }
      ]
    }
  }'
```

Then create a client grant for each resource server. The following example grants access to the My Account API. Repeat it with the `https://YOUR_DOMAIN/my-org/` audience and the My Organization API scopes.

```bash wrap lines theme={null}
curl --request POST \
  --url "https://YOUR_DOMAIN/api/v2/client-grants" \
  --header "authorization: Bearer {managementApiToken}" \
  --header "content-type: application/json" \
  --data '{
    "client_id": "{portalClientId}",
    "audience": "https://YOUR_DOMAIN/me/",
    "subject_type": "user",
    "scope": [
      "read:me:factors",
      "read:me:authentication_methods",
      "create:me:authentication_methods",
      "delete:me:authentication_methods"
    ]
  }'
```

## Settings you must not change

These settings change how Portals work and should not be changed.

> [!WARNING]
>
> Other application settings can also affect how the Portal behaves. Test any change on a development tenant first.

* **Do not enable DPoP.** The portal server is a confidential client and does not use sender-constrained tokens.
* **Do not enable refresh token rotation.** Portals do not support it.
* **Do not share an application between Portals.** Each Portal needs its own application.
* **Do not set the refresh token inactivity lifetime below 1 hour.** The portal session lasts 1 hour of inactivity. A shorter refresh token lifetime makes API calls fail before the Portal asks the user to sign in again.
* **Do not add grant types or scopes that the Portal does not use.** For example, do not enable the `client_credentials` grant.
* **Do not add a Management API grant to the portal application.** Forms that update users should use a separate machine-to-machine application.

## Scenario settings

Some use cases need extra settings on the portal application. Review the scenarios in this section and apply the settings that match how your users open the Portal.

### Native application

To open the Portal from a native application, the portal application must accept [session transfer tokens](https://auth0.com/docs/authenticate/single-sign-on/native-to-web/configure-implement-native-to-web.md#create-and-manage-session-transfer-tokens) that arrive in the URL. Add this to the portal application:

```json wrap lines theme={null}
{
  "session_transfer": {
    "allowed_authentication_methods": ["query"],
    "enforce_device_binding": "ip"
  }
}
```

Configure the native application to create session transfer tokens. To learn more, read [Configure and Implement Native to Web SSO](https://auth0.com/docs/authenticate/single-sign-on/native-to-web/configure-implement-native-to-web.md). Then follow [Access Portals](https://auth0.com/docs/customize/portals/access-portals.md#open-a-portal-from-a-native-application).

### Organization context

To open the Portal with the `organization` parameter, the portal application must allow [Organizations](https://auth0.com/docs/manage-users/organizations.md):

```json wrap lines theme={null}
{
  "organization_usage": "allow"
}
```

The recommended configuration already includes this value, with the default `no_prompt` login flow. With them, always send `organization` when you open a business Portal. To learn more, read [Define Organization Behavior](https://auth0.com/docs/manage-users/organizations/configure-organizations/define-organization-behavior.md) and [Access Portals](https://auth0.com/docs/customize/portals/access-portals.md#open-a-portal-in-an-organization-context).

### Forms that update users

A form whose [Flow](https://auth0.com/docs/customize/forms/flows.md) updates users calls the Management API through a [Forms vault](https://auth0.com/docs/customize/forms/vaults.md) connection. Create a separate machine-to-machine application for that connection and grant it only the scopes that the Flow needs, such as `update:users` and `update:users_app_metadata`. To learn more, read [Auth0 Vault Connections](https://auth0.com/docs/customize/forms/vaults/auth0.md).

## Link the application to the Portal

**Auth0 Dashboard**

1. Navigate to [**Auth0 Dashboard > Portals**](https://manage.auth0.com/dashboard/#/universal-portals) and select **Create Portal**, or open an existing Portal.
2. Enter a **Name** and a **Slug**, and select the application. The slug becomes part of the portal URL.
3. Select **Create**.

**Management API**

```bash wrap lines theme={null}
curl --request POST \
  --url "https://YOUR_DOMAIN/api/v2/portals" \
  --header "authorization: Bearer {managementApiToken}" \
  --header "content-type: application/json" \
  --data '{
    "name": "{portalName}",
    "slug": "{slug}",
    "client": {
      "token_endpoint_auth_method": "client_secret_post",
      "client_id": "{portalClientId}",
      "client_secret": "{portalClientSecret}"
    }
  }'
```

The `client_secret` is write-only. Auth0 never returns it. The portal API supports only `client_secret_post`. A duplicate `slug` returns `409 Conflict`.

## Validate enabled connections

Users can sign in to the Portal with any connection that is enabled for the portal application. Before you share the Portal, make sure that at least one connection your users need is enabled.

1. Navigate to [**Auth0 Dashboard > Applications**](https://manage.auth0.com/dashboard/#/applications/list) and select the portal application.
2. Select the **Connections** tab.
3. Turn on the connections your users need. If no connection is enabled, users cannot sign in to the Portal.

To learn more, read [Update Application Connections](https://auth0.com/docs/get-started/applications/update-application-connections.md).

If the **Enable Application Connections** tenant setting is on, the portal application gets all of the tenant's current connections, including the one the Quickstart creates. To learn more, read [Tenant Settings](https://auth0.com/docs/get-started/tenant-settings#advanced).

## Verify the configuration

Open `https://YOUR_DOMAIN/portals/{slug}` and sign in with a test user. Open a page with a Universal Component. If the component shows an error, read [Troubleshoot Universal Portals](https://auth0.com/docs/customize/portals/troubleshoot-portals.md).

## Next steps

> **[Troubleshoot Universal Portals](https://auth0.com/docs/customize/portals/troubleshoot-portals.md)**
>
> Fix API errors, sign-in problems, and organization problems.

> **[Access Portals](https://auth0.com/docs/customize/portals/access-portals.md)**
>
> Send users from your applications to the Portal.
