Tapis Authentication#
Tapis Authentication into TACC
by Silvia Mazzoni, DesignSafe, 2025
Tapis connects you to TACC. You can submit jobs as well as monitor them – whether you submitted them using Tapis or any other DesignSafe Application that uses it, such as the OpenSeesMP and OpenSeesSP job submitted from the web portal.
Just like you need a badge to access a secure building, you need a token to access different tools and data inside the Tapis platform. Tapis tokens are digital keys that prove your identity when you’re using Tapis services.
When you log in to Tapis (using your username and password or other method), you get a token. This token is what tells Tapis, “I’m allowed to use these tools.” The token is a long string with apparently-random characters.
This module will teach you how to obtain a tapis token, how to save it to a file, and how to retreive it from this file. We will create a python function with the content we generate in this module and will use this function in the next modules.
Tapis Authentication Tokens#
Just like you need a badge to access a secure building, you need a token to access different tools and data inside the Tapis platform. Tapis tokens are digital keys that prove your identity when you’re using Tapis services.
When you log in to Tapis (using your username and password or other method), you get a token. This token is what tells Tapis, “I’m allowed to use these tools.” The token is a long string with apparently-random characters.
Why Tokens?#
Tapis is built to help researchers and developers run jobs, access data, manage systems, and more — often from different computers and applications. Tokens make this secure and flexible.
Tokens let Tapis:
Know who you are
Check what you’re allowed to do
Let you interact with the system without needing to send your password every time
How Tokens Work (Simplified)#
You log in You use your credentials to log in through the Tapis authentication service (either directly or through a script or app).
Tapis gives you a token The system returns a token — a long string of letters and numbers — that represents you for a limited amount of time.
You use the token in your requests When you want to call a Tapis API (e.g., to run a job or access files), you include the token in the header of your request:
Authorization: Bearer <your_token_here>
Tapis checks the token Behind the scenes, Tapis checks that the token is valid and sees what you’re allowed to do. If everything checks out, the action goes through.
Tokens expire Tokens are only valid for a short period (usually minutes). After that, you’ll need to log in again to get a new one.
Save the Token#
You can save this token to a file and use it until it expires. This way you don’t have to enter your password as often.
Saving your token means:
You don’t need to log in again every time you run a script (as long as the token hasn’t expired).
You can load it into other scripts without exposing your username/password.
Tips for Beginners
Treat your token like a password — never share it or post it publicly.
You don’t need to remember your token — just copy and paste it when needed.
Connect#
We’ll use a Python utility function to authenticate and establish a session with Tapis:
Checks if a valid token file already exists
If no token is found — or the token has expired — it will prompt you to enter your username and password
You can also pass your username as a function argument to avoid typing it interactively
This simplifies your workflow and ensures you’re always connected with valid credentials — without the need to manage tokens manually.
Ths function is available in CommunityData, so you can use it across all your DesignSafe notebooks with a single command.
connect_tapis.py
# /home/jupyter/CommunityData/OpenSees/TrainingMaterial/training-OpenSees-on-DesignSafe/OpsUtils/OpsUtils/Tapis/connect_tapis.py
def connect_tapis(token_filePath: str = "~/.tapis_tokens.json",
base_url: str = "https://designsafe.tapis.io",
username: str = "",
password: str = "",
force_connect: bool = False):
"""
Connect to a Tapis platform (e.g., DesignSafe) with automatic token handling.
Behavior
--------
- Looks for a saved access token at `token_filePath` (default: ~/.tapis_tokens.json).
- If present and not expired, uses it to create an authenticated Tapis client.
- If missing/expired, or when `force_connect=True`, prompts for credentials,
requests new tokens, and saves them back to `token_filePath`.
- Prints expiration details for transparency.
Parameters
----------
token_filePath : str, default "~/.tapis_tokens.json"
Path to the JSON file that stores the Tapis `access_token` and `expires_at`.
base_url : str, default "https://designsafe.tapis.io"
Tapis API endpoint base URL.
username : str, default ""
Optional preset username. If empty, you will be prompted.
password : str, default ""
Optional preset password. If empty, you will be prompted (securely).
force_connect : bool, default False
If True, ignores any valid saved token and performs a fresh login.
Returns
-------
object
An authenticated `Tapis` client object ready to use.
Notes
-----
- The token file stores: `{"access_token": "...", "expires_at": "...ISO8601..."}`.
- Expiry timestamps are treated as UTC if no timezone is present.
- If the saved token cannot be parsed/validated, a fresh login is performed.
Example
-------
t = connect_tapis() # use saved token or prompt as needed
jobs = t.jobs.getJobList() # now you're authenticated
Author
------
Silvia Mazzoni, DesignSafe (silviamazzoni@yahoo.com)
Date
----
2025-08-14
Version
-------
1.0
"""
from tapipy.tapis import Tapis
from getpass import getpass
from datetime import datetime, timezone
import json
import os
def _parse_expires_at(s: str) -> datetime | None:
"""Parse ISO8601 expiry, accepting 'Z' and naive strings; return aware UTC dt or None."""
if not s:
return None
try:
# normalize trailing 'Z' to +00:00
s_norm = s.replace("Z", "+00:00")
dt = datetime.fromisoformat(s_norm)
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
return dt.astimezone(timezone.utc)
except Exception:
return None
def getTokensLoop():
username = getpass("Username: ")
password = getpass("Password: ")
t = Tapis(base_url=base_url, username=username, password=password)
try:
t.get_tokens()
return t
except Exception as e:
print(f" ** Warning ** could get token : {e},\n TRY AGAIN!")
t= getTokensLoop()
return t
print(" -- Checking Tapis token --")
token_path = os.path.expanduser(token_filePath)
now = datetime.now(timezone.utc)
t = None
saved_expires_at = None
valid_token = False
# Try to load a saved token
if os.path.exists(token_path):
try:
with open(token_path, "r") as f:
tokens = json.load(f)
saved_expires_at = _parse_expires_at(tokens.get("expires_at"))
if tokens.get("access_token") and saved_expires_at and saved_expires_at > now:
print(" Token loaded from file. Token is still valid!")
t = Tapis(base_url=base_url, access_token=tokens["access_token"])
valid_token = True
else:
print(" Token file found but token is missing/expired.")
if saved_expires_at:
print(" Token expired at:", saved_expires_at.isoformat())
except Exception as e:
print(f" Could not read/parse token file ({token_path}): {e}")
else:
print(" No saved tokens found.")
if force_connect:
print(" Forcing a connection to Tapis (fresh login).")
if not valid_token or force_connect:
print("-- Connect to Tapis --")
if not username:
# username isn't sensitive; echoing can help avoid typos, but keeping your original choice:
username = getpass("Username: ")
if not password:
password = getpass("Password: ")
t = Tapis(base_url=base_url, username=username, password=password)
try:
t.get_tokens()
except Exception as e:
print(f" ** Warning ** could get token : {e},\n TRY AGAIN!")
t= getTokensLoop()
# Save the new token back to the chosen path
try:
tokens = {
"access_token": t.access_token.access_token,
"expires_at": t.access_token.expires_at.isoformat(),
}
os.makedirs(os.path.dirname(token_path), exist_ok=True)
with open(token_path, "w") as f:
json.dump(tokens, f)
print(f" Token saved to {token_path}")
saved_expires_at = _parse_expires_at(tokens["expires_at"])
except Exception as e:
print(f" Warning: could not save token to {token_path}: {e}")
# Print expiry info (use stored/parsed date if needed)
exp_to_show = saved_expires_at
try:
# if available, prefer the client object's value
if getattr(t, "access_token", None) and getattr(t.access_token, "expires_at", None):
exp_to_show = _parse_expires_at(str(t.access_token.expires_at)) or exp_to_show
except Exception:
pass
if exp_to_show:
print(" Token expires at:", exp_to_show.isoformat())
print(" Token expires in:", str(exp_to_show - now))
else:
print(" Token expiry time unavailable.")
print("-- LOG IN SUCCESSFUL! --")
return t
# NOTE: Your browser's autofill may not work here.
t=OpsUtils.connect_tapis(force_connect=True)
-- Checking Tapis token --
Token file found but token is missing/expired.
Token expired at: 2025-09-02T23:45:26+00:00
Forcing a connection to Tapis (fresh login).
-- Connect to Tapis --
** Warning ** could get token : message: Invalid username/password combination.,
TRY AGAIN!
** Warning ** could get token : message: Either a refresh_token or a username and password are required for get_tokens().,
TRY AGAIN!
** Warning ** could get token : message: Invalid username/password combination.,
TRY AGAIN!
Token saved to /home/jupyter/.tapis_tokens.json
Token expires at: 2025-09-05T02:30:48+00:00
Token expires in: 4:00:33.043411
-- LOG IN SUCCESSFUL! --
# NOTE: If your files have disappeared from the jupyter file browser in the left pane, please take a screenshot and submit a ticket to DesignSafe.
# Save all your work and reload the page in the browser -- the files will reappear.