Authentication#
At the high level, authenticating with the LabArchives API is a task delegated to LabArchives itself. LabArchives provides two primary systems, a time-based Authentication token, and a callback-based auth flow similar to OAuth.
Both systems return authentication tokens that can be used alongside a user email in the login() method.
Since the time-based system requires the user to find the External App authentication button and copy the email and token into the login method (or to your app), it is generally more preferable to use the callback flow, which has the additional benefit of allowing Single Sign-On.
Choosing an Auth Pattern#
Use the flow that matches where your code runs:
Scenario |
Recommended approach |
Why |
|---|---|---|
Local scripts, notebooks, ad-hoc analysis on a workstation |
Fastest “happy path” and easiest onboarding. |
|
Headless hosts (containers, CI workers, cron jobs, orchestrators) |
|
Avoids dependence on a local browser session. |
One-off/manual testing without callback wiring |
|
Useful for quick experiments when interactive callback flow is not available. |
Interactive Authentication#
labapi provides a series of methods to assist with the authenticating of users. The most plug-and-play is to use the default_authenticate() method.
This method prompts the user to activate a link that will bring them to the LabArchives sign in page, and calls back to a temporary local server and immediately signs the user in.
Note
When the labapi[builtin-auth] extra dependencies are installed, default_authenticate() can open a siloed browser window for the user to authenticate in.
from labapi import Client
with Client() as client:
user = client.default_authenticate()
labapi provides two primary methods for authenticating users with LabArchives: an interactive browser-based flow and a manual flow that can be integrated into server-based applications.
Server-Based Authentication#
For deeper integrations with other systems, or for use in servers, labapi provides access to the generate_auth_url() function.
This function generates a LabArchives authentication url that eventually redirects to the callback_url passed to it, allowed application developers to implement the credential capture on their own servers.
For service environments, this is the recommended flow:
Your app exposes a callback URL (for example
https://my-service.example.org/labarchives/callback).Your app sends users to
client.generate_auth_url(callback_url).LabArchives redirects back to your callback URL with
emailandauth_codequery parameters.Your callback handler exchanges those values via
login().Your service stores only what it needs for subsequent calls, following your organization’s secret-management policy.
Note
labapi currently does not provide a separate client-credentials style service principal flow.
Service integrations should use callback capture + login() for user context, or External App authentication where operationally appropriate.
Example Flask App#
import flask
from labapi import Client
app = flask.Flask(__name__)
@app.route("/login")
def login():
with Client() as client:
callback_url = flask.url_for("callback", _external=True)
auth_url = client.generate_auth_url(callback_url)
return flask.redirect(auth_url)
@app.route("/callback")
def callback():
email = flask.request.args.get("email")
auth_code = flask.request.args.get("auth_code")
if not email or not auth_code:
return "Authentication failed.", 400
with Client() as client:
user = client.login(email, auth_code)
notebook_names = list(user.notebooks)
return f"Logged in as {user.id}. Notebooks: {notebook_names}"
if __name__ == "__main__":
app.run(port=8080)
Advanced Local Callback Control#
If you want to keep browser handling separate from callback capture, use
generate_auth_url() and
collect_auth_response() directly:
from labapi import Client
with Client() as client:
callback_path = "/auth/local-demo/"
auth_url = client.generate_auth_url(
f"http://127.0.0.1:8089{callback_path}"
)
with client.collect_auth_response(
port=8089,
callback_path=callback_path,
) as auth_response_collector:
print("Open authentication URL in your browser:")
print(auth_url)
user = auth_response_collector.wait()
Headless and CI Workflows#
In non-interactive environments (CI, scheduled jobs, or batch workers), avoid default_authenticate() because it expects a browser + local callback listener.
Instead, use one-hour codes for job execution and use login() directly:
export API_URL="https://api.labarchives.com"
export ACCESS_KEYID="your_access_key"
export ACCESS_PWD="your_access_password"
export AUTH_EMAIL="service.user@example.org"
export AUTH_KEY="short_lived_auth_code"
import os
from labapi import Client
client = Client()
user = client.login(
os.environ["AUTH_EMAIL"],
os.environ["AUTH_KEY"],
)
# continue your automated task...
# notebook = user.notebooks["Automation Notebook"]
Note
AUTH_EMAIL and AUTH_KEY here are application-level environment
variable names chosen by this example. Unlike API_URL,
ACCESS_KEYID, and ACCESS_PWD, they are not auto-loaded by
Client.
Operational guidance for automation:
Treat
auth_codevalues as secrets; keep them in your CI secret store rather than source control.Prefer short-lived credentials and regular rotation.
Build your own refresh/re-auth step in orchestration when codes expire.
Use least-privilege LabArchives users for automated jobs.