Security

Tiled employs modern web security standards to enforce access control with minimum inconvenience to the user.

There are four use cases for the Tiled server.

  1. Secure single-user server, analogous to how people use jupyter notebook

  2. Public data service

  3. Private multi-user data service

  4. Multi-user data service with some public and some private content

We address each in turn below.

Secure single-user server

In this mode, a single user or small group of highly trusted users have access to a Tiled server protected by a secret access token. This is the default mode. For those familiar with Jupyter, this is very similar to how jupyter notebook works.

At startup, a secret token is generated and logged in the terminal.

$ tiled serve pyobject tiled.examples.generated_minimal:tree

    Use the following URL to connect to Tiled:

    "http://127.0.0.1:8000?api_key=a4062c3dd6ab2af0d28fdb7eb278dd985c462ecf08d39f33233554c7fdaa42e7"

where the token after api_key= will be different each time you start the server. Once you have visited this URL with your web browser or the Tiled Python client, a cookie will be set in your client and you won’t need to use the token again. It is valid indefinitely.

For horizontally-scaled deployments where you need multiple instances of the server to share the same secret, you can set it with a CLI option

tiled serve ... --api-key=YOUR_SECRET

or via an environment variable

TILED_SINGLE_USER_API_KEY=YOUR_SECRET tiled serve ...

or via the configuration parameter

authentication:
  single_user_api_key: "..."

When the secret is set manually it this way, it is not logged in the terminal.

Note

When generating a secret, is important to produce a difficult-to-guess random number, and make it different each time you start up a server. Two equally good ways to generate a secure secret…

With openssl:

openssl rand -hex 32

With python:

python -c "import secrets; print(secrets.token_hex(32))"

Public data service

Tiled can serve a public data repository with no authentication required. To launch it in this mode, use the --public flag as in

tiled serve {pyobject, directory, config} --public ...

When the server is started in this way, it will log a notice like the following:

$ tiled serve pyobject --public tiled.examples.generated_minimal:tree

    Tiled server is running in "public" mode, permitting open, anonymous access.
    Any data that is not specifically controlled with an access policy
    will be visible to anyone who can connect to this server.

Alternatively, if using a configuration file as in

tiled serve config ...

include the configuration:

authentication:
  allow_anonymous_access: true

This is a complete working example:

# config.yml
authentication:
  allow_anonymous_access: true
trees:
  - path: /
    tree: tiled.examples.generated_minimal:tree
tiled serve config config.yml

As above, a notice will be logged that the server is public.

Private multi-user data service

In this mode, users must log in to access anything other than the root GET / and documentation GET /docs routes.

Tiled is designed to integrate with external user-management systems via a pluggable Authenticator interface. For those familiar with JupyterHub, these are very similar to JupyterHub Authenticators. Authenticators fall into two groups:

  • Authenticators that accept user credentials directly, following the OAuth2 and OpenAPI standards as shown below, and validate the credentials using some underlying authentication mechanism, such as PAM.

  • Authenticators that use an external service such as Google or ORCID to validate the user identity, without directly handling credentials in Tiled.

This mode requires configuration files to be used, as in

tiled serve config path/to/config_file(s)

in order to specify the Authenticator and, when applicable, any parameters. The shorthands tiled serve pyobject ... and tiled serve directory ... do not currently support this mode. See below for complete working examples.

The server implements “sliding sessions”, meaning that the user provides their login credentials once and the server keep their session alive for as long as they are actively using it—up to some optional, configurable limit.

You may configure:

  • The maximum time to keep an inactive session alive (default is one week)

  • The maximum session lifetime (default is unlimited)

  • Access token lifetime. This is internal from the user’s point of view It should be short. (Default 15 minutes.)

See Authentication Details for advanced customization options and additional details.

Authenticate with local system accounts

Tiled includes a PAMAuthenticator for logging in with local user accounts using a username and password. It requires one additional dependency:

pip install pamela

The configuration file(s) should include:

authentication:
  authenticator: tiled.authenticators:PAMAuthenticator

Here is a complete working example:

# pam_config.yml
authentication:
  providers:
    - authenticator: tiled.authenticators:PAMAuthenticator
      # This 'provider' can be any string; it is used to differentiate
      # authentication providers when multiple ones are supported.
      provider: local
trees:
  - path: /
    tree: tiled.examples.generated_minimal:tree
tiled serve config pam_config.yml

Authenticate using a system user account and password.

Authenticate with OpenID Connect Providers

Tiled includes an OIDCAuthenticator for logging in with third-party identity providers including ORCID, Google, and many others using the web standard OpenID Connect. In this mode, Tiled does not directly handle users’ login credentials. Instead, it provides a link to open in the browser, log in to the third-party service, and obtain an access code that will be accepted by Tiled.

This uses the same technology that supports web-based flows like “Log in to Website X with Google!” but it does so in a way that works from command-line tools, scripts, Jupyter notebooks, and other applications. It works like this:

User: Hello, Tiled! Please let me in. Tiled Server: Go to this URL and come back with an access code. User (in web browser): Hello OIDC Provider {ORCID, Google, etc.}, Tiled sent me. OIDC Provider: Do you authorize Tiled to see your account info? User (in web browser): Yes. OIDC Provider: directs browser to Tiled Serer Tiled Server: The OIDC provider has vouched that you are {username}. Copy/paste this access code.

The OIDCAuthenticator requires an additional dependency. (Depending on how you installed Tiled, you may already have it because it is required by Tiled’s Python client.)

pip install httpx
  1. Deploy Tiled with HTTPS.

  2. Register your application with the OIDC Provider. You will be asked to provide redirect URIs. Enter two: https://.../api/v1/auth/provider/SOME_NAME_HERE/code and https://.../api/v1/auth/provider/SOME_NAME_HERE/device_code. You will be given a Client ID and Client Secret.

  3. It is recommended to set the Client Secret as an environment variable, such as OIDC_CLIENT_SECRET, and reference that from configuration file as shown below.

  4. Obtain the OIDC provider’s public key(s). These are published by the OIDC provider. Starting from a URL like:

    Navigate to the link under the key jwks_uri. These public key(s) are designed to prevent man-in-the-middle attacks. They may be rotated over time.

The configuration file(s) must include the following.

authentication:
  providers:
  - provider: SOME_NAME_HERE
    authenticator: tiled.authenticators:OIDCAuthenticator
    args:
      # All of these are given by the OIDC provider you register
      # your application.
      client_id: ...
      client_secret: ${OIDC_CLIENT_SECRET}  # reference an environment variable
      # These come from the OIDC provider as described above.
      token_uri: ...
      authorization_endpoint: ...
      public_keys:
        - kty: ...
          e: ...
          use: ...
          kid: ...
          n: ...
          alg: ...
      confirmation_message: "You have logged in with ... as {id}."

There are example configurations for ORCID and Google in the directory example_configs/ in the Tiled source repository.

Toy examples for testing and development

The DictionaryAuthenticator authenticates using usernames and passwords specified directly in the configuration. The passwords may be extracted from environment variables, as shown. This is not a robust user management system and should only for used for development and demos.

# dictionary_config.yml
authentication:
  providers:
  - provider: toy
    authenticator: tiled.authenticators:DictionaryAuthenticator
    args:
      users_to_passwords:
        alice: ${ALICE_PASSWORD}
        bob: ${BOB_PASSWORD}
        cara: ${CARA_PASSWORD}
trees:
  - path: /
    tree: tiled.examples.generated_minimal:tree
ALICE_PASSWORD=secret1 BOB_PASSWORD=secret2 CARA_PASSWORD=secret3 tiled serve config dictionary_config.yml

The DummyAuthenticator accepts any username and password combination.

# dummy_config.yml
authentication:
  providers:
  - provider: toy
    authenticator: tiled.authenticators:DummyAuthenticator
trees:
  - path: /
    tree: tiled.examples.generated_minimal:tree
tiled serve config dummy_config.yml

To control which users can see which entries in the Trees, see Access Control.

Multi-user data service with some public and some private content

When an Authenticator is used in conjunction with Access Control, certain entries may be designated as “public”, visible to any user. By default, visitors still need to be authenticated (as any user) to see these entries. To make such entries visible to anonymous, unauthenticated users as well, include the configuration:

authentication:
  allow_anonymous_access: true

See also Service Configuration Reference.