# Technical Guide

### 1. BridgeXR

The BridgeXR management application consists of a simple frontend and backend. We provide everything needed to deploy both applications and an example configuration in the deployment package. Keep in mind that the provided configuration is an example and needs to be adjusted to be deployed for production use if you choose to do so. The provided configuration example showcases all mandatory settings needed to run the application.

### 2. Azure Integration

We provide integration with Azure Active Directory B2C SSO (3. SSO Integration), Azure Key Vault (5.2 Configuration) and Azure Blob Storage (5.1.2 Object Storage).

### 3. SSO Integration

#### 3.1 Azure Active Directory B2C

In order to integrate with Azure Active Directory B2C SSO we need the following parameters:

**Frontend:**

* Application (client) ID
* Authority URL

**Backend:**

* JWKS URI (found in the openid-configuration of the Azure AD B2C tenant)

For the frontend, the `Application (client) ID` and `Authority URL` are needed to configure the MSAL library used for authentication and have to be set in the `msal.json` found in the `public` directory of the supplied frontend files.

For the backend, the `JWKS URI` is needed to validate the tokens issued by Azure AD B2C and has to be set in the `OidcKeysURL` configuration key.

The `API permissions` needed are as follows:

* `User.Read`
* `email`
* `profile`

The redirect URIs under `Authentication` need to be configured as follows:

* Single-page application
  * `https://<host>/msal-login-popup` — needed for the Web Dashboard
  * `http://localhost:51273/StreamingAssets/callback.html` — needed for the Unity Wizard
* Android
  * `msauth://com.zoe.bridgexr.client/<hash>` — needed for the Android client (for more information about the hash consult the app documentation or contact us)
* Mobile and desktop applications
  * `unityhub://editor/authentication.editorAddons.editorLink/oauth2/`
  * `http://localhost:8080/zoe/bridgexr/oauth2/`

Refer to [msal-client-application-configuration](https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-application-configuration) for more information.

#### 3.2 Others

If a different SSO integration is needed, please contact us.

If no SSO integration is provided, the only way to log in is with credentials manually managed in the database. BridgeXR does not provide management facilities for user credentials.

### 4. Frontend

The frontend application is delivered as a folder of static files that must be served as a Single Page Application (SPA) on your own infrastructure.

The routing is handled client-side, so the web server should always return the `index.html` file for any unknown paths, rather than a 404.

The frontend requires `/api` to be mapped to the backend while stripping the `/api` prefix (e.g., `https://frontend.local/api/foo/bar` gets redirected to `http[s]://backend.local/foo/bar` internally).

The frontend files must be served over HTTPS, and the following headers must be set to allow the WebGPU component to work:

* `Cross-Origin-Opener-Policy: same-origin`
* `Cross-Origin-Embedder-Policy: require-corp`

Refer to [SharedArrayBuffer#security\_requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements) for more information.

For files served from `/WebGL/` the appropriate gzip headers must be set for the browser to transparently use the compressed files.

We provide an example nginx configuration for serving the frontend and proxying to the backend. If you use a different web server and encounter deployment issues, please contact us.

### 5. Backend

The backend consists of a standalone binary for `x86-64-linux` that can be deployed via most contemporary mechanisms. If a different target is needed, please contact us.

Configuration is handled via environment variables, configuration files, or integrations with configuration providers, as outlined in §5.2 Configuration.

There are no additional requirements regarding the deployment method, so deploying on a Virtual Machine or Container from any provider should be possible.

We provide a prefilled (as far as possible) example config file and Dockerfile for the backend. If you encounter issues running the provided binary on your chosen infrastructure, please contact us.

#### 5.1 Dependencies on External Services

**Postgres**

The backend uses a Postgres database to store most of its data.

Database migrations are handled by the backend, which assumes full access to the database defined in the application's connection string.

We do not provide backups on our side, so setting up a backup strategy for the database is the responsibility of the deployer.

**Object Storage**

For binary data, we defer to mature object storage solutions, and provide integrations with Azure Blob Storage and S3-compatible object storage.

We do not provide backups on our side, so setting up a backup strategy for the object storage is the responsibility of the deployer.

**Azure Blob Storage**

We provide integration with Azure Blob Storage for storing data. If you encounter issues with our Azure Blob Storage integration, please contact us.

**S3-compatible Object Storage**

We provide integration with S3-compatible object storage solutions for storing data.

This is tested using MinIO and AWS S3. If you encounter issues with a different S3-compatible storage solution, please contact us.

#### 5.2 Configuration

The backend can be configured via:

* Configuration files (`config.{json,yaml}`, `.env`)
* Command-line flags
* Environment variables
* Azure Key Vault

The specific keys which can be configured are found in the Appendix.

***

### Appendix: Configuration Keys

| Name                       | Description                                                                | CLI                                                                   | JSON/YAML                                                                  | Env/Dotenv                                                              | Azure Key Vault                                                                            |
| -------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Host                       | Host the main api server binds to                                          | `--host 0.0.0.0`                                                      | `{"HOST": "0.0.0.0"}`                                                      | `RCL_HOST=0.0.0.0`                                                      | `Name: host \| Secret Value: 0.0.0.0`                                                      |
| Port                       | Port the main api server binds to                                          | `--port 8080`                                                         | `{"PORT": "8080"}`                                                         | `RCL_PORT=8080`                                                         | `Name: port \| Secret Value: 8080`                                                         |
| Log Level                  | Log level for the server                                                   | `--log-level INFO`                                                    | `{"LOG_LEVEL": "INFO"}`                                                    | `RCL_LOG_LEVEL=INFO`                                                    | `Name: log-level \| Secret Value: INFO`                                                    |
| Jwt Duration               | Duration of JWT tokens created by the application                          | `--jwt-duration 1h`                                                   | `{"JWT_DURATION": "1h"}`                                                   | `RCL_JWT_DURATION=1h`                                                   | `Name: jwt-duration \| Secret Value: 1h`                                                   |
| Refresh Duration           | Duration of refresh tokens created by the application                      | `--refresh-duration 0`                                                | `{"REFRESH_DURATION": "0"}`                                                | `RCL_REFRESH_DURATION=0`                                                | `Name: refresh-duration \| Secret Value: 0`                                                |
| Jwt Private Key Path       | Path to JWT private key                                                    | `--jwt-private-key-path /opt/jwt.pem`                                 | `{"JWT_PRIVATE_KEY_PATH": "/opt/jwt.pem"}`                                 | `RCL_JWT_PRIVATE_KEY_PATH=/opt/jwt.pem`                                 | `Name: jwt-private-key-path \| Secret Value: /opt/jwt.pem`                                 |
| Db Connection String       | Connection string to the postgres database                                 | `--db-connection-string postgres://user:pass@localhost:5432/BridgeXR` | `{"DB_CONNECTION_STRING": "postgres://user:pass@localhost:5432/BridgeXR"}` | `RCL_DB_CONNECTION_STRING=postgres://user:pass@localhost:5432/BridgeXR` | `Name: db-connection-string \| Secret Value: postgres://user:pass@localhost:5432/BridgeXR` |
| Aws Endpoint               | AWS endpoint parameter for S3-compatible object storage                    | `--aws-endpoint minio.example.com:9900`                               | `{"AWS_ENDPOINT": "minio.example.com:9900"}`                               | `RCL_AWS_ENDPOINT=minio.example.com:9900`                               | `Name: aws-endpoint \| Secret Value: minio.example.com:9900`                               |
| Aws Access Key ID          | AWS access key id parameter for S3-compatible object storage               | `--aws-access-key-id minio_user`                                      | `{"AWS_ACCESS_KEY_ID": "minio_user"}`                                      | `RCL_AWS_ACCESS_KEY_ID=minio_user`                                      | `Name: aws-access-key-id \| Secret Value: minio_user`                                      |
| Aws Secret Access Key      | AWS secret access key parameter for S3-compatible object storage           | `--aws-secret-access-key minio_password`                              | `{"AWS_SECRET_ACCESS_KEY": "minio_password"}`                              | `RCL_AWS_SECRET_ACCESS_KEY=minio_password`                              | `Name: aws-secret-access-key \| Secret Value: minio_password`                              |
| Aws Bucket Name            | AWS bucket parameter for S3-compatible object storage                      | `--aws-bucket-name bridge-xr`                                         | `{"AWS_BUCKET_NAME": "bridge-xr"}`                                         | `RCL_AWS_BUCKET_NAME=bridge-xr`                                         | `Name: aws-bucket-name \| Secret Value: bridge-xr`                                         |
| Aws Endpoint Secure        | Use HTTPS for access to S3-compatible object storage                       | `--aws-endpoint-secure true`                                          | `{"AWS_ENDPOINT_SECURE": "true"}`                                          | `RCL_AWS_ENDPOINT_SECURE=true`                                          | `Name: aws-endpoint-secure \| Secret Value: true`                                          |
| Aws Endpoint Public Secure | Use HTTPS for access to the public url of the S3-compatible object storage | `--aws-endpoint-public-secure true`                                   | `{"AWS_ENDPOINT_PUBLIC_SECURE": "true"}`                                   | `RCL_AWS_ENDPOINT_PUBLIC_SECURE=true`                                   | `Name: aws-endpoint-public-secure \| Secret Value: true`                                   |
| Key Vault Url              | URL to the key vault                                                       | `--key-vault-url https://example.vault.azure.net/`                    | `{"KEY_VAULT_URL": "https://example.vault.azure.net/"}`                    | `RCL_KEY_VAULT_URL=https://example.vault.azure.net/`                    | This parameter cannot be configured via Azure Key Vault                                    |
| Jwt Azure Key Name         | Name of the key in Azure Key Vault used for JWT signing and verification   | `--jwt-azure-key-name jwt-key`                                        | `{"JWT_AZURE_KEY_NAME": "jwt-key"}`                                        | `RCL_JWT_AZURE_KEY_NAME=jwt-key`                                        | `Name: jwt-azure-key-name \| Secret Value: jwt-key`                                        |
| Azure Blob Container Name  | Name of the Azure Blob Storage container                                   | `--azure-blob-container-name ExampleContainer`                        | `{"AZURE_BLOB_CONTAINER_NAME": "ExampleContainer"}`                        | `RCL_AZURE_BLOB_CONTAINER_NAME=ExampleContainer`                        | `Name: azure-blob-container-name \| Secret Value: ExampleContainer`                        |
| Azure Blob Account Name    | Name of the Azure Blob Storage account                                     | `--azure-blob-account-name ExampleAccount`                            | `{"AZURE_BLOB_ACCOUNT_NAME": "ExampleAccount"}`                            | `RCL_AZURE_BLOB_ACCOUNT_NAME=ExampleAccount`                            | `Name: azure-blob-account-name \| Secret Value: ExampleAccount`                            |
| Azure Blob Account Key     | Account key for the Azure Blob Storage account                             | `--azure-blob-account-key ExampleKey`                                 | `{"AZURE_BLOB_ACCOUNT_KEY": "ExampleKey"}`                                 | `RCL_AZURE_BLOB_ACCOUNT_KEY=ExampleKey`                                 | `Name: azure-blob-account-key \| Secret Value: ExampleKey`                                 |
| Azure Blob Account URL     | URL of the Azure Blob Storage account                                      | `--azure-blob-account-url https://example.blob.core.windows.net/`     | `{"AZURE_BLOB_ACCOUNT_URL": "https://example.blob.core.windows.net/"}`     | `RCL_AZURE_BLOB_ACCOUNT_URL=https://example.blob.core.windows.net/`     | `Name: azure-blob-account-url \| Secret Value: https://example.blob.core.windows.net/`     |
| Oidc Keys URL              | URL to fetch OIDC keys used for Microsoft identity platform integration    | `--oidc-keys-url example.com/discovery/v2.0/keys`                     | `{"OIDC_KEYS_URL": "example.com/discovery/v2.0/keys"}`                     | `RCL_OIDC_KEYS_URL=example.com/discovery/v2.0/keys`                     | `Name: oidc-keys-url \| Secret Value: example.com/discovery/v2.0/keys`                     |
| Oidc Keys Refresh Interval | Interval to refresh the OIDC keys                                          | `--oidc-keys-refresh-interval 1h`                                     | `{"OIDC_KEYS_REFRESH_INTERVAL": "1h"}`                                     | `RCL_OIDC_KEYS_REFRESH_INTERVAL=1h`                                     | `Name: oidc-keys-refresh-interval \| Secret Value: 1h`                                     |
| Licensing Host             | Host the licensing server listens on                                       | `--licensing-host`                                                    | `{"LICENSING_HOST": ""}`                                                   | `RCL_LICENSING_HOST=`                                                   | `Name: licensing-host \| Secret Value:`                                                    |
| Licensing Port             | Port the licensing server listens on                                       | `--licensing-port`                                                    | `{"LICENSING_PORT": ""}`                                                   | `RCL_LICENSING_PORT=`                                                   | `Name: licensing-port \| Secret Value:`                                                    |
| Licensing Client Cert Path | Path to the licensing client certificate                                   | `--licensing-client-cert-path /opt/licensing_client_cert.pem`         | `{"LICENSING_CLIENT_CERT_PATH": "/opt/licensing_client_cert.pem"}`         | `RCL_LICENSING_CLIENT_CERT_PATH=/opt/licensing_client_cert.pem`         | `Name: licensing-client-cert-path \| Secret Value: /opt/licensing_client_cert.pem`         |
| Licensing Client Key Path  | Path to the licensing client key                                           | `--licensing-client-key-path /opt/licensing_client_key.pem`           | `{"LICENSING_CLIENT_KEY_PATH": "/opt/licensing_client_key.pem"}`           | `RCL_LICENSING_CLIENT_KEY_PATH=/opt/licensing_client_key.pem`           | `Name: licensing-client-key-path \| Secret Value: /opt/licensing_client_key.pem`           |
