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

# App security and identity

Secure your Domino App with access control and permissions. This page explains how to control who can view and edit your apps, how to manage access requests from users, and how apps can identify viewers and act on their behalf.

Domino provides three levels of identity propagation for Apps, each offering different capabilities and security levels:

* **Basic identity**: Know who is viewing your app (username only)

* **Enhanced identity**: Verify user identity with tokens (username, email, user ID)

* **Extended identity**: Act on behalf of users with their full permission (access data, submit jobs, manage projects)

## Access controls and permissions

Control who can view and edit your Apps to protect sensitive data and manage collaboration.

**Edit permissions** are inherited from the project level because apps are part of projects. When you add someone as a project collaborator, they can automatically edit any apps in that project. To add editors, add them as collaborators to the project where the app resides.

**View permissions** are set at the app level and can follow one of two modes:

* **Restricted**: Only users you explicitly list and project collaborators can view (or edit). Use **Restricted** mode when your app handles sensitive data or is intended for specific team members only.

* **Anyone in Domino**: Anyone with a Domino account can view (or edit). Use **Anyone in Domino** for internal tools, dashboards, or resources that all employees should access.

### Discovery vs. viewing

Domino distinguishes between:

* **Discovering an App**: Seeing it listed in App views

* **Viewing an App**: Opening and using it

This separation lets you create a browsable app catalog where users can explore available apps and request access to ones they need, without giving them immediate access to potentially sensitive content.

### Restricted mode options

When an app’s view permissions are set to **Restricted**, additional options appear:

* **Globally discoverable**: All Domino users can find the app and request access to view it

* **Viewers**: App owners can manage the list of users who can view the app, and accept or deny requests for access

### Where to set permissions

You can set these permissions when publishing an App in the **Access and sharing** tab, or at any time after publication by selecting **Share** from the App list view.

After you set permissions, users with view access can open and interact with your app. Users without access see the app listed (if globally discoverable) with a **Request access** button.

## Request and grant access

Access requests create a self-service model for app discovery. Users can find and request access to apps they need without contacting IT or app owners directly, while owners maintain full control over who can view their apps.

### Request access to an app

If you see **Request access** next to an app in the Domino apps list view, the app is globally discoverable but you don’t have view permissions yet. To request access:

1. Find the app in the Domino Apps list view.

2. Click **Request access**.

You’ll receive a Domino notification and an email when the owner grants you access.

### Grant access to your app

When someone requests access to your app, you’ll receive a notification in Domino and an email. To grant or deny access:

1. Click the notification link or go to your app and click **Share**.

2. Review open requests.

3. Click **Accept or Deny** for each request.

## App identity and authentication

Domino apps can identify and authenticate viewers at three different levels. Each level provides different information and capabilities to help you build personalized, secure applications.

* **Basic identity** tells you who is viewing your app by passing the username in an HTTP header. Use this for loading user-specific defaults, preferences, or displaying personalized content.

* **Enhanced identity** verifies user identity with signed tokens that include username, email, and user ID. Use this when you need cryptographic proof of identity or additional user attributes beyond the username.

* **Extended identity** lets your app act on behalf of users with their full permissions. Your app can access user data, submit jobs, manage projects, and perform other authorized actions in Domino. Users must explicitly grant consent before the app receives these permissions.

### Basic identity propagation

Use basic identity when you need to know who is viewing your app. This is useful for loading user-specific defaults, preferences, or displaying personalized content. Domino passes the username in an HTTP header called `domino-username`.

If users who aren’t logged in to Domino view your apps, the `domino-username` header value is `Anonymous`.

<Note>
  Identity headers are only available in frameworks that support proxied HTTP headers. Flask and Dash support them by default. Shiny requires that you use Server Pro.
</Note>

**Example: Display the viewer’s username**\
This Flask example shows how to get the Domino username of an app viewer:

```bash theme={null}
#!/usr/bin/env bash
export LC_ALL=C.UTF-8
export LANG=C.UTF-8
export FLASK_APP=app.py
export FLASK_DEBUG=1
python -m flask run --host=0.0.0.0
```

Here is a simple `app.py` file that renders a template named `index.html`. This app imports `request` from `flask`, which gives you access to the headers of the active HTTP request. Note that port selection is flexible and port `8888` is no longer required.

```python theme={null}
import flask
from flask import request, redirect, url_for

class ReverseProxied(object):
  def __init__(self, app):
      self.app = app
  def __call__(self, environ, start_response):
      script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
      if script_name:
          environ['SCRIPT_NAME'] = script_name
          path_info = environ['PATH_INFO']
          if path_info.startswith(script_name):
              environ['PATH_INFO'] = path_info[len(script_name):]
      return self.app(environ, start_response)

app = flask.Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)

# Homepage which uses a template file
@app.route('/')
def index_page():
  return flask.render_template("index.html")
```

Create a template file at `templates/index.html`:

```python theme={null}
<!DOCTYPE html>
<html>
  <body>
    <h1>Your username is {{ request.headers.get("domino-username") }}</h1>
  </body>
</html>
```

When you host this app in Domino and open it, you’ll see the username that matches the app user.

### Enhanced identity propagation

Use enhanced identity when you need verified user information beyond just the username. This approach validates the token to make sure that identity information is authentic and hasn’t been tampered with.

When the `SecureIdentityPropagationToAppsEnabled` feature flag is enabled, Domino hosts apps at a different URL structure (https\://\<domino-domain>/apps/\<app-id>/) and passes a JWT authorization token in the Authorization HTTP Header.

You can verify the token’s integrity and decode it to get the user’s username, email, and Domino userID. The token audience is scoped to a limited set of Domino endpoints, restricting what operations the app can perform.

<Note>
  Identity headers are only available in frameworks that support proxied HTTP headers. Flask and Dash support them by default. Shiny requires that you use Server Pro.
</Note>

**Configure the base path**\
Some application servers need to know their base path to correctly handle routing, generate URLs, and serve static assets. Without proper base path configuration, your app may fail to load resources or generate broken links.

If your application server requires a base path configuration, read it from the `DOMINO_RUN_HOST_PATH` environment variable.

**Example: Verify and decode JWT token**\
Extract the token from the `Authorization` header:

```python theme={null}
def extract_token(self, headers):
  auth_header = headers.get('Authorization', '')
  return auth_header[7:] if auth_header.startswith('Bearer ') else None
```

Verify and decode the token (using this example JWKS):

```python theme={null}
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from jwt import decode, get_unverified_header
import base64, json, jwt, requests

def verify_and_decode_jwt_token(token):
    keycloak_domain = "http://keycloak-http.domino-platform"
    jwks_url = f"{keycloak_domain}/auth/realms/DominoRealm/protocol/openid-connect/certs"

    jwks_dict = requests.get(jwks_url).json()
    kid = get_unverified_header(token).get('kid')

    public_key = None
    for key in jwks_dict['keys']:
        if key['kid'] == kid:
            x5c = key['x5c'][0]
            cert = x509.load_der_x509_certificate(base64.b64decode(x5c), default_backend())
            public_key = cert.public_key()
            break
    if not public_key:
        raise ValueError("No public key found for kid")

    pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )

    return jwt.decode(token, pem, algorithms=['RS256'], audience="apps")
```

Here is a decoded payload example:

```python theme={null}
{
  "sub": "66d9fc7a538b60bef7c02c9c",
  "preferred_username": "userName",
  "email": "userName@domain.com",
  "given_name": "givenName",
  "family_name": "familyName"
}
```

### Extended identity propagation

Use extended identity when your app needs to perform actions on behalf of users. Your app can access user data, submit jobs, manage projects, and perform other actions the user is authorized to do in Domino.

When the `com.cerebro.domino.apps.extendedIdentityPropagationToAppsEnabled` configuration control is enabled, apps can request permission to act on behalf of users. Users must explicitly grant consent before the app receives these permissions.

<Warning>
  This feature is enabled by default. Extending identity propagation gives the app access to the viewing user's credentials in addition to the publisher's credentials. It doesn't lock the app into using the viewing user's credentials, the app code has access to both and decides which is appropriate for each action. Individual apps must opt in to extended identity propagation, and only SysAdmins or CloudAdmins can publish apps that have opted in.
</Warning>

**How it works**

1. Users see a consent prompt when they open an app that requests extended permissions.

2. If users grant consent, the app can retrieve a token with full user scope.

3. The app implements code to retrieve the user’s token from the Authorization header.

4. The app calls Domino APIs as the user using this token.

5. Users can choose to remember their consent for an extended period.

Consent has an expiration date and is auditable. The default expiration is 8 hours, but users can specify up to 30 days for an expiration date on the App consent page.

**Retrieve user token**

```python theme={null}
auth_token = request.headers.get('Authorization', '')
token = auth_token[7:] if auth_token.startswith('Bearer ') else ""
```

Without extended identity propagation enabled, the same code can retrieve a token, but it has limited scope instead of full user permissions.

To enable the `com.cerebro.domino.apps.extendedIdentityPropagationToAppsEnabled` setting, the `SecureIdentityPropagationToAppsEnabled` feature flag must also be set to `true`. The app has access to the user’s full credentials only if the publisher enables extended propagation in the app and the user grants consent.

<Warning>
  Apps with extended permissions can access all data the user can access and perform actions as the user. Only enable this for apps you trust. Once you have enabled extended identity propagation on an app, it can’t be disabled.
</Warning>

**To enable extended identity propagation**

1. The configuration record must be enabled.

2. The app must have extended app propagation enabled.

3. The app’s code must actually use the viewer’s token.

4. The viewer must consent.

**Example: Use extended permissions**\
The application base path can be read from the `DOMINO_RUN_HOST_PATH` environment variable and used to set the base path in your server configuration:

```python theme={null}
import os

from flask import (
    Flask,
)

class ReverseProxied(object):
    def __init__(
        self,
        app,
    ):
        self.app = app

    def __call__(
        self,
        environ,
        start_response,
    ):
        script_name = os.environ.get('DOMINO_RUN_HOST_PATH', '')
        if script_name:
            environ["SCRIPT_NAME"] = script_name
            path_info = environ["PATH_INFO"]
            if path_info.startswith(script_name):
                environ["PATH_INFO"] = path_info[len(script_name) :]
        # Setting wsgi.url_scheme from Headers set by proxy before app
        scheme = environ.get(
            "HTTP_X_SCHEME",
            "https",
        )
        if scheme:
            environ["wsgi.url_scheme"] = scheme
        return self.app(
            environ,
            start_response,
        )

app = Flask(__name__)

from app import (
    views,
)

app.wsgi_app = ReverseProxied(app.wsgi_app)
```

## Next steps

* [Publish and share an app](/cloud/platform-capabilities/features/apps/publish-an-app): Learn how to publish apps and manage permissions.

* [Allow external resources in Apps](/cloud/platform-capabilities/features/apps/authentication-and-identity/whitelist-resources): Apps may be blocked from loading content unless those URLs are explicitly allowlisted.


## Related topics

- [Authentication and identity for Apps](/cloud/platform-capabilities/features/apps/authentication-and-identity/index.md)
- [Publish and share an App](/cloud/platform-capabilities/features/apps/publish-an-app.md)
- [Apps in Domino](/cloud/platform-capabilities/features/apps/apps-in-domino/index.md)
- [Administer identity and access control](/cloud/admin/security-and-compliance/auth-identity-access-control.md)
