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

# Anonymous runtime access

> Run processes and UI flows for unauthenticated users using the built-in Anonymous role and the Share modal's public-access option.

<Info>
  A runtime app can be configured for unauthenticated end users. Anonymous users start processes and UI flows from a public link, with no login required.
</Info>

## Overview

Anonymous runtime access lets an app serve users who have no FlowX identity. A typical use case is a public form, a quote calculator, or an appointment booking page reachable from a marketing site.

Two independent gates must both be open for a request to be served anonymously:

<Steps>
  <Step title="The app must be shared publicly">
    In the Share modal, **General access** is set to **Everyone with the link**. Apps default to **Only invited users and groups**.
  </Step>

  <Step title="The resource must allow the Anonymous role">
    The specific process or UI flow being started must have the **Anonymous** role assigned in its Permissions tab.
  </Step>
</Steps>

If either gate is closed, the runtime returns `403 You don't have access to this feature.` Mixed-access is supported — the same app can serve authenticated users with their assigned roles and anonymous users with the Anonymous role.

<Frame>
  ![Public-access toggle in the Share modal](https://s3.eu-west-1.amazonaws.com/docx.flowx.ai/5.9/anonymous-share-modal.png)
</Frame>

***

## The Anonymous role

`Anonymous` is a **built-in, system-level role**. It represents any user who arrives without a valid authentication token.

| Property                            | Value                                                                    |
| ----------------------------------- | ------------------------------------------------------------------------ |
| **Role type**                       | System (built-in)                                                        |
| **Editable**                        | No — name, scope, and allowed operations are fixed                       |
| **Deletable**                       | No                                                                       |
| **Allowed operations**              | `VIEW`, `EXECUTE`, `SELF_ASSIGN`                                         |
| **Selectable operations in the UI** | `VIEW` and `EXECUTE` only — `SELF_ASSIGN` is auto-populated and required |
| **Default on a project**            | Not added — admin opts in via **End User Roles** in Version settings     |

<Info>
  `SELF_ASSIGN` is required because starting a process needs both `EXECUTE` and `SELF_ASSIGN`. The role auto-populates the three operations and locks `SELF_ASSIGN` so the role always behaves consistently across processes.
</Info>

***

## Make an app publicly accessible

<Steps>
  <Step title="Add the Anonymous role to the project">
    Open the project's **Version settings → End User Roles**, then add **Anonymous** to the available roles.

    Until the role is on the version, the Share modal's general-access dropdown stays disabled.
  </Step>

  <Step title="Open the Share modal">
    From the project header, click **Share**.
  </Step>

  <Step title="Set General access to Everyone with the link">
    Under **Who has access → General access**, switch from **Only invited users and groups** to **Everyone with the link**.

    <Tip>
      Switching back to **Only invited users and groups** at any point closes the public gate immediately. Existing anonymous sessions in flight will start returning `403 Anonymous access not enabled for this application` on their next request.
    </Tip>
  </Step>

  <Step title="Save and copy the share link">
    Save the Share modal. The runtime app is now reachable to anyone with the URL — subject to the per-resource role check below.
  </Step>
</Steps>

***

## Configure anonymous on a resource

The Anonymous role must be explicitly assigned to each process, UI flow, or reusable UI template you want runnable without authentication.

<Tabs>
  <Tab title="Process">
    Open the process and go to **Permissions**.

    1. Add **Anonymous** to the role list (only available when the role is on the version).
    2. The role's row shows `VIEW`, `SELF_ASSIGN`, and `EXECUTE` pre-populated. Toggle `VIEW` or `EXECUTE` as needed. All other operations are greyed out.
    3. Adding Anonymous is **additive** — it does not affect other roles on the process.

    Anonymous can also be added to a swimlane. The component hide/disable rules below depend on this assignment.
  </Tab>

  <Tab title="UI Flow">
    Open the UI flow and go to **Settings → Permissions**.

    Add **Anonymous** to the role list. The same additive behaviour applies — other roles are preserved.

    Anonymous on a UI flow is required for that flow to be startable from a public URL, and for any integration workflows started from inside the flow to be reachable anonymously.
  </Tab>

  <Tab title="Reusable UI template">
    Reusable UI templates inherit role availability from **Process Version → End User Roles**. Once Anonymous is added there, it becomes selectable as a role-based hide/disable condition inside the template.
  </Tab>
</Tabs>

***

## Component visibility for anonymous users

UI Designer hide/disable rules support the Anonymous role in the **Role** condition type. The role must already be assigned at the right scope:

| Component lives in…    | Anonymous must be on…                    |
| ---------------------- | ---------------------------------------- |
| A process node         | The corresponding **swimlane**           |
| A UI flow              | The UI flow's **Permissions** tab        |
| A reusable UI template | The process version's **End User Roles** |

Common patterns:

* **Hide for anonymous** — show a "Sign in to continue" CTA only when the user is anonymous; hide an action button (e.g. "Save to account") for anonymous users.
* **Disable for anonymous** — keep a field visible but read-only; the same field becomes editable for authenticated users.

***

## Runtime behaviour scenarios

| #  | App general access            | Resource has Anonymous role               | User                                              | Outcome                                                                                                                       |
| -- | ----------------------------- | ----------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| 1a | Everyone with the link        | Yes                                       | Anonymous                                         | Starts and uses the resource with Anonymous permissions.                                                                      |
| 1b | Everyone with the link        | Yes (Anonymous is the only role)          | Authenticated                                     | Starts with the same permissions Anonymous grants — the logged-in user is effectively treated as anonymous for that resource. |
| 1c | Everyone with the link        | Yes (Anonymous + at least one other role) | Authenticated and assigned one of the other roles | Uses the assigned role; Anonymous is ignored.                                                                                 |
| 2a | Only invited users and groups | n/a                                       | Anonymous                                         | `403 You don't have access to this feature.`                                                                                  |
| 2b | Everyone with the link        | No                                        | Anonymous                                         | `403 You don't have access to this feature.`                                                                                  |

***

## The anonymous session

Anonymous traffic is isolated using a session ID — there is no user identity to bind state to.

* **Header:** `X-Fx-Anonymous-Session-Id`
* **Issued by:** the backend, on the first anonymous request that doesn't already carry one. The new session ID comes back in the response header `X-Fx-Anonymous-Session-Id` (exposed via `Access-Control-Expose-Headers`; the exposed-header list is controlled by the `APPLICATION_CORS_EXPOSEDHEADERS` env var, which carries this header by default).
* **Maintained by:** the SDK / container app. After receiving the session ID, the client must include it on every subsequent anonymous request.
* **Scope:** one anonymous session can only access the process and UI flow instances it created. Another session that knows the `processInstanceUuid` cannot read or act on it.
* **Lifetime:** fire-and-forget. Closing the browser ends the session. There is no resume mechanism in 5.9.0.

<Warning>
  **Tokens take precedence over anonymous mode.** If the client sends an `Authorization: Bearer …` header, the backend treats the request as authenticated and ignores the anonymous session ID. There is no fallback to anonymous when a bearer token is invalid or expired — the request returns `401`.

  A common bug: a user logs in on `/private`, then opens `/public` in the same browser. The persisted bearer is attached to public-route requests and the backend returns the authenticated user's data. Container apps must scrub the `Authorization` header on public routes — see [SDK behaviour](#sdk-and-container-app-behaviour) below.
</Warning>

### Public build, public assets

Once a runtime build is published with the Anonymous role and the app is shared publicly, the build is considered **public**. All assets inside it are reachable anonymously — except UI flows and processes that have not been explicitly opened to the Anonymous role.

Public assets in a public build:

* **Enumerations** — `/rtm/api/runtime/app/{appId}/build/{buildId}/rt/enumeration/...`
* **Substitution tags** — `/rtm/api/runtime/app/{appId}/build/{buildId}/rt/substitutiontag`
* **Media files** — `/rtm/api/runtime/app/{appId}/build/{buildId}/rt/mediafile`
* **Themes** — `/cms/api/wks/{workspaceId}/themes/uuid/{themeId}/platform/{platform}/compiled` (globally unauthenticated)
* **Fonts** — `/cms/api/fonts` (globally unauthenticated)

Restricted assets (require authentication and a role grant):

* UI flows not configured with Anonymous
* Processes not configured with Anonymous
* Chat, task manager, and view-scoped endpoints — see [Restricted endpoints](#restricted-endpoints) below

***

## SDK and container app behaviour

### Renderer initialization

Process and UI flow renderer components decide their mode **at initialization** from the `authToken` parameter:

* `authToken` **present (non-null)** → renderer runs in authenticated mode. All outgoing requests carry the bearer token. If the token expires mid-flow the renderer surfaces `401` errors (existing behaviour).
* `authToken` **absent (null/undefined)** → renderer runs in anonymous mode. The renderer omits the `Authorization` header and uses `X-Fx-Anonymous-Session-Id` instead.

<Warning>
  **The mode is locked at init.** Switching `authToken` from `null` to a value after the renderer has started will not flip it into authenticated mode, and vice versa. If you need both modes in the same container app, mount separate renderer instances on separate routes (e.g. `/public` and `/private`).
</Warning>

### Container apps

A container app that hosts both public and authenticated routes must guarantee that public routes do **not** pass an `Authorization` header to the renderer. The renderer uses an isolated HTTP client at runtime, so whatever the container does for its own pages does not automatically leak in — but if the container reads a token from `localStorage` and supplies it to the renderer, the token-precedence rule above applies and anonymous mode is silently bypassed.

The recommended pattern:

* Public route (e.g. `/public/...`) → mount renderer with `authToken={null}`
* Private route (e.g. `/private/...`) → mount renderer with `authToken={accessToken}`
* Clear any stored bearer when the user navigates from `/private` to `/public`.

### Platform support

| Capability                           | Web (React, Angular)      | iOS                       | Android                   |
| ------------------------------------ | ------------------------- | ------------------------- | ------------------------- |
| Anonymous start of process / UI flow | ✅                         | ✅                         | ✅                         |
| Anonymous session ID handling        | ✅                         | ✅                         | ✅                         |
| File uploads with anonymous session  | ✅                         | ✅                         | ✅                         |
| SSE streams (limited types)          | ✅                         | ✅                         | ✅                         |
| Task manager surfaces                | n/a — restricted          | n/a — restricted          | n/a — restricted          |
| Chat surfaces                        | n/a — restricted in 5.9.0 | n/a — restricted in 5.9.0 | n/a — restricted in 5.9.0 |

***

## What anonymous users can call

Anonymous traffic is allowed on a curated set of runtime endpoints. The full reference is the SDK endpoint table — the summary below is grouped by capability. Endpoints flagged **session ID required** must include `X-Fx-Anonymous-Session-Id`; the backend rejects requests where the session ID does not match the entity it refers to (`403 Anonymous session not found for entity`).

### Allowed

| Capability                                                    | Endpoints                                                                                                                                                                                                                                                                                                           | Session ID                                                         |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Build info                                                    | `/rtm/api/runtime/wks/{wks}/app/{appId}/build/info`<br />`/rtm/api/runtime/process-instance/{piUuid}/build/info`<br />`/rtm/api/runtime/ui-flow-session/{sessionUuid}/build/info`                                                                                                                                   | Required on the last two                                           |
| Process — start                                               | `POST /rtm/api/runtime/app/{appId}/build/{buildId}/process-name/{name}/start`<br />`POST /rtm/api/runtime/app/{appId}/build/{buildId}/process-rdi/{rid}/start`                                                                                                                                                      | Optional on start — issued by BE if missing                        |
| Process — status, data, details, actions, dismiss, subprocess | `GET /api/runtime/process/{piUuid}/status`<br />`GET .../data`, `.../data/{templateConfigId}/context/{ctx}`<br />`GET .../node/{nodeDefId}/context/{ctx}/details`<br />`POST .../token/{tokenUuid}/ui-action/{uiActionUuid}/context/{ctx}/execute`<br />`POST .../ui-action/.../subprocess`<br />`POST .../dismiss` | Required                                                           |
| UI flow — start                                               | `POST /rtm/api/runtime/app/{appId}/build/{buildId}/ui-flows/{name}`<br />`POST /rtm/api/runtime/app/{appId}/build/{buildId}/ui-flow-rdi/{rid}`                                                                                                                                                                      | Optional on start                                                  |
| UI flow — status, file upload                                 | `GET /api/runtime/ui-flow-session/{uuid}/status`<br />`POST /api/runtime/wks/{wks}/appId/{appId}/ui-flow/{uuid}/upload`<br />`POST .../upload-multiple`                                                                                                                                                             | Required                                                           |
| Workflow — start from UI flow                                 | `POST /rtm/api/runtime/wks/{wks}/app/{appId}/rdi/{rid}/start-workflow?uiFlowSessionUuid={uuid}`                                                                                                                                                                                                                     | Required. The user must also be authorized for the parent UI flow. |
| Data model paths (gated by Anonymous role on the resource)    | `GET /rtm/api/runtime/process-instance/{piUuid}/data-model-paths`<br />`GET .../app/{appId}/build/{buildId}/process-name/{name}/data-model-paths` (and equivalent for processes by `rdi`, and UI flows by `ui-flow-session`, `ui-flow-name`, `ui-flow-rdi`)                                                         | Required on the process-instance and ui-flow-session forms         |
| CMS — enumerations, substitution tags, media                  | See [Public build, public assets](#public-build-public-assets) above                                                                                                                                                                                                                                                | n/a                                                                |
| Themes, fonts                                                 | Globally unauthenticated                                                                                                                                                                                                                                                                                            | n/a                                                                |
| SSE — process instance                                        | `GET /api/events/process-instance/{piUuid}?offset={offset}`                                                                                                                                                                                                                                                         | Required                                                           |
| SSE — generic, allowed types only                             | `GET /api/events/generic/{id}?type={type}&offset={offset}`<br />**Allowed types:** `UI_FLOW_WORKFLOW_RESPONSE`, `UI_FLOW_FILE_UPLOAD`, `UI_FLOW_FILE_UPLOAD_MULTIPLE`                                                                                                                                               | Required — used to correlate the entity with the session           |
| File uploads (UI flow scope)                                  | `POST /document/internal/wks/{wks}/temp-files/upload`<br />`POST .../upload-multiple`                                                                                                                                                                                                                               | Required                                                           |

### Restricted endpoints

The following are **never** served anonymously, regardless of the public gates:

* **Task manager** — every `/rtm/api/runtime/app/.../view/...` and `/task/api/tasks/...` endpoint
* **Chat** — `/rtm/api/runtime/wks/.../conversations`, chat-workflow start, chat-session upload (postponed past 5.9.0)
* **View-based SSE** — `/api/events/view/{viewId}`
* **Generic SSE other types** — `CHAT_WORKFLOW_RESPONSE`, `CHAT_FILE_UPLOAD`
* **Internal runtime endpoints** — anything under `/rtm/api/runtime-internal/wks/.../app-version/...` (including `process-resource-id/.../start/test` and `start/email-trigger`)
* **Languages** — `/cms/api/languages` is not exposed for anonymous in 5.9.0

***

## Error responses

| Status | Body `detail`                                             | Cause                                                                                                              |
| ------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| 403    | `You don't have access to this feature.`                  | Either the app is private, or the resource does not allow the Anonymous role.                                      |
| 403    | `Anonymous access not enabled for this application`       | Request hit a workflow / resource in an app that is not publicly shared.                                           |
| 403    | `Anonymous session not found for entity`                  | The `X-Fx-Anonymous-Session-Id` header does not match the session the entity was created with.                     |
| 401    | `Full authentication is required to access this resource` | The endpoint requires authentication and no bearer token was provided.                                             |
| 401    | (any)                                                     | A bearer token was sent but invalid or expired. The backend does **not** fall back to anonymous mode in this case. |

***

## CORS requirements

Two headers must be in the gateway's `Access-Control-Allow-Headers` allow-list and `Access-Control-Expose-Headers` response list:

```yaml theme={"system"}
Access-Control-Allow-Headers:
  - X-Fx-Anonymous-Session-Id
  - Fx-BuildId

Access-Control-Expose-Headers:
  - X-Fx-Anonymous-Session-Id
```

`Fx-BuildId` is required on SSE connections so the backend can route the stream to the correct build when no user identity is present.

The default FlowX `commons-security-lib` CORS configuration includes both headers from 5.9.0. If you override CORS in your deployment, make sure these are preserved.

***

## Limitations (5.9.0)

* **Fire-and-forget sessions** — closing the browser ends the session. No resumption.
* **No task assignment** to anonymous users. Anonymous can start and act on a process they own via the session ID; they cannot be assigned an existing task.
* **Mode is locked at renderer init** — see [Renderer initialization](#renderer-initialization).
* **No anonymous chat** in 5.9.0.
* **No anonymous languages endpoint** (`/cms/api/languages`).
* **Subprocesses** — `data-model-paths` calls for subprocesses are gated by the same session-ID check as the root process instance.
* **Anonymous role cannot be removed or renamed.** It can only be added to or removed from a project's End User Roles.

***

## Related resources

<CardGroup cols={2}>
  <Card title="Swimlanes" icon="layer-group" href="./swimlanes">
    Configuring swimlane roles, including Anonymous, for process steps.
  </Card>

  <Card title="Business filters" icon="filter" href="./business-filters">
    Other role-driven runtime filtering.
  </Card>

  <Card title="Roles & permissions matrix" icon="table" href="../../../setup-guides/access-management/roles-permissions-matrix">
    Full list of system and end-user roles, with allowed operations.
  </Card>

  <Card title="Web SDK renderer" icon="react" href="../../../sdks/react-renderer">
    `authToken` initialization rules and container-app patterns.
  </Card>
</CardGroup>
