Authentication & Impersonation
The octostar-python-client library mandates to define an explicit client to call functions from the Octostar API. Clients allow for security and permissions to be respected whenever applications wish to perform CRUD operations against the platform, as well as any other type of request. App developers should take great care in ensuring they impersonate the user with the correct level of access.
Which users can an app impersonate?​
Clients have an authorization (a JWT) with which they make requests against the Octostar API. These clients represent users, which are a high-level abstraction describing a user of the platform. Apps can impersonate the following users:
- The Launching User, who is the one who DEPLOYED the app;
- The Running User, who is the one OPENING and using the app via its user interface or transforms;
- The Developer User, who is the user TESTING the app, only accessible during local development
YOU ARE WARNED
You should see clear warnings in your logs/console whenever back-end functions have been called with a developer client or without an explicit client invocation. In both cases, the library will attempt to fallback to a JWT contained in the app files or in an environment variable. This is highly unsafe if performed in a production setting.
There are three ways to define a user:
- At a function-level, using
impersonating_XXX_user()decorator - At a context-level, using
as_XXX_user()context manager - Manually, using
User(make_client())
See the sections below for some examples of these.
Impersonating the Launching User​
By default, when deploying an application, octostar-python-client will create a default client which is set to the user DEPLOYING the app (usually with some admin role).
You can therefore run the functions of the library as they are, however this will cause warnings, as it is much preferrable to explicitly instantiate it:
from octostar.client import as_launching_user, impersonating_launching_user
with as_launching_user() as client:
client.execute(query_ontology.sync, "SELECT count() FROM dtimbr.person")
@impersonating_launching_user()
def my_func(client):
client.execute(query_ontology.sync, "SELECT count() FROM dtimbr.person")
my_func()
LAUNCHING USER = ADMIN ACCESS
Be careful! The launching user is the user who DEPLOYS the app, not the user who is currently interacting with it! Make sure any calls done by this user cannot contain information with privileged access or, if it does, that the user interacting with the app cannot see it.
The credentials of the user who launched the app are in the file /etc/secrets/OS_JWT, which changes over time.
Impersonating the Running User (streamlit)​
To impersonate the user running the app, there is a corresponding set of functions in streamlit-octostar-utils
from streamlit_octostar_utils.octostar.client import as_running_user, impersonating_running_user
with as_running_user() as client:
client.execute(query_ontology.sync, "SELECT count() FROM dtimbr.person")
@impersonating_running_user()
def my_func(client):
client.execute(query_ontology.sync, "SELECT count() FROM dtimbr.person")
my_func()
The credentials of the running user are updated from the browser and stored in streamlit's session state, and therefore require browser interactions to be working.
Impersonating the Running User (flask, fastapi)​
Since these servers are stateless, the JWT of the running user must be supplied manually and a corresponding client be instantiated within the endpoint:
from octostar.client import make_client
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def my_func(jwt: str):
client = make_client(jwt)
return client.execute(query_ontology.sync, "SELECT count() FROM dtimbr.person")
Alternatively, the launching user can be used (with care!).
Impersonating the Developer User​
The developer user can be impersonated in a similar manner as the launching user, however the necessary parameters must be supplied, either as environment variables or as parameters:
from octostar.client import as_developer_user, impersonating_developer_user
import os
from dotenv import load_dotenv