A CLI tool and Python module for making REST API calls to T Cloud Public endpoints.
Supports bearer token, AK/SK (SDK-HMAC-SHA256), and metadata server authentication.
It is more of a tool to use for creating integration scripts rather than outright application.
- Python 3.10+
requestslibrary- Optional:
icecream(debug logging, falls back gracefully) - Optional:
pyyaml(YAML output format)
# Core dependencies
pip install requests
# Optional:
pip install icecream pyyaml
# For interactive login (urwid-based TUI form):
pip install urwidOr install via pip from source:
pip install .This installs two console scripts:
| Command | Description |
|---|---|
tcurl |
Main CLI tool for API calls, credentials, etc. |
tcurl-login |
Interactive TUI login (username/password/OTP form) |
# As a standalone script
python tcurl.py [global-opts] <command> [command-opts]
# Or using the installed console scripts:
tcurl [global-opts] <command> [command-opts]
tcurl-login [options]| Option | Description |
|---|---|
-v, --verbose |
Show additional information |
-V, --version |
Show version and exit |
| Command | Description |
|---|---|
login |
Issue a bearer token (password or unscoped token exchange) |
logout |
Revoke a previously issued token |
| Command | Description |
|---|---|
metadata |
Retrieve temporary AK/SK from the metadata server |
aksk |
Issue temporary AK/SK credentials from a bearer token |
| Command | Description |
|---|---|
get |
Make a GET request |
post |
Make a POST request (requires body) |
put |
Make a PUT request (requires body) |
patch |
Make a PATCH request (requires body) |
delete |
Make a DELETE request |
head |
Make a HEAD request |
options |
Make an OPTIONS request |
Every command except logout supports the --format / -f option:
| Format | Description |
|---|---|
raw |
Space-joined values (default) |
json |
Pretty-printed JSON |
yaml |
YAML output (requires pyyaml) |
shell |
Shell export statements for sourcing |
Credentials are resolved in this order:
- Command-line arguments
- Metadata server (
http://169.254.169.254/openstack/latest/securitykey) - Environment variables
# Environment
export OS_AUTH_TOKEN=...
python tcurl.py get https://...
# Command line
python tcurl.py get --token=eyJ... https://...# Environment
export OS_ACCESS_KEY=...
export OS_SECRET_KEY=...
export OS_SECURITY_TOKEN=... # optional, for temp credentials
# Command line
python tcurl.py get --ak=... --sk=... https://...When doing AK/SK calls, you can scope the request with any of these mutually exclusive options:
| Option | Description |
|---|---|
--project-id |
Scope to a specific project ID |
--project-name |
Scope to a project by name |
--domain-id |
Scope to a specific domain ID |
# Fetch credentials first
eval $(python tcurl.py metadata --format shell)
# Then use them
python tcurl.py get https://...Alternatively, pass --metadata directly to any REST verb:
python tcurl.py get --metadata https://...You can also use a custom metadata URL with --url:
# In two steps
python tcurl.py metadata --url=http://custom.metadata/securitykey --format shell
# Or inline with any REST verb
python tcurl.py get --url=http://custom.metadata/securitykey https://...All REST verb commands (get, post, put, patch, delete, head, options)
accept these authentication options (mutually exclusive):
| Option | Description |
|---|---|
--token / -t |
Bearer token (or env OS_AUTH_TOKEN / OS_TOKEN) |
--ak / -a |
Access Key (or env OS_ACCESS_KEY) |
--sk / -s |
Secret Key (or env OS_SECRET_KEY) |
--securitytoken / -T |
Security token for temp credentials (or env OS_SECURITY_TOKEN) |
--metadata / -m |
Fetch credentials from the standard metadata endpoint |
--url / -U |
Fetch credentials from a custom metadata URL |
And these general options:
| Option | Description |
|---|---|
--header / -H |
Additional header in Key:Value format (repeatable) |
--format / -f |
Output format: raw, json, yaml, shell |
# Using username + password
python tcurl.py login --username=user@example.com --password=... --domain=OTC0000xxxx
# Interactive (prompts for missing credentials via stdin)
python tcurl.py login --interactive
# Interactive with urwid-based TUI form (requires urwid)
tcurl-login
# Interactive with Virtual MFA OTP
python tcurl.py login --interactive --totp=123456
# Exchange an unscoped token for a scoped one
python tcurl.py login --token=eyJ... --project=eu-de_project
# Scope to a region
python tcurl.py login --username=... --password=... --domain=... --region=eu-de
# Custom auth URL
python tcurl.py login --username=... --password=... --domain=... --auth-url=https://iam.eu-de.otc.t-systems.comOptions:
| Option | Description |
|---|---|
--username / -u |
Username for password-based authentication |
--password / -P |
Password (or env OS_PASSWORD) |
--domain / -D |
User domain name, e.g. OTC0000xxxx (or env OS_USER_DOMAIN_NAME) |
--token / -t |
Unscoped token to exchange for a scoped one |
--project / -p |
Scope to a project name (derives region from prefix) |
--region / -R |
Scope to a region (or env OS_TENANT_NAME) |
--auth-url / -A |
Custom auth URL (or env OS_AUTH_URL) |
--interactive / -i |
Prompt for credentials interactively |
--totp |
Virtual MFA one-time passcode |
The login command outputs the token and expiry in the selected format
(--format json is recommended for inspection).
# Revoke a specific token
python tcurl.py logout eyJ...
# Revoke the token from the environment and export shell commands
python tcurl.py logout --shellThe --shell flag (or --format shell) outputs export statements suitable
for eval, clearing the OS_AUTH_TOKEN variable after revocation.
# Issue temporary credentials valid for 15 minutes (default)
python tcurl.py aksk --token=eyJ...
# Custom duration (up to 24 hours = 86400 seconds)
python tcurl.py aksk --maxage=3600 --token=eyJ...
# Using environment variable for the token
export OS_AUTH_TOKEN=eyJ...
python tcurl.py aksk
# With a custom region or auth URL
python tcurl.py aksk --region=eu-de --maxage=7200Options:
| Option | Description |
|---|---|
--token / -t |
Bearer token (or env OS_AUTH_TOKEN / OS_TOKEN) |
--maxage / -M |
Max lifetime in seconds (default: 900 / 15 min) |
--region / -R |
Region for auth URL (or env OS_TENANT_NAME) |
--auth-url / -A |
Custom auth URL (or env OS_AUTH_URL) |
--format / -f |
Output format: raw, json, yaml, shell |
The issued AK/SK will have the same permissions as the original bearer token.
| Path | Description |
|---|---|
tcurl.py |
CLI tool and importable module |
tcurl_login.py |
Interactive TUI login form (urwid-based) |
setup.py |
Package installer / distribution |
tests/ |
Test scripts and examples |
docs/ |
Sphinx documentation source |
_attic/ |
Archived scripts (not part of the project) |
DEVNOTES.md |
Developer notes |
tcurl.py and tcurl_login.py can be imported and used programmatically:
from tcurl import (
creds, add_headers, add_project_id, add_domain_id,
metadata_config, resolve_auth_url,
login, logout, temp_aksk,
OTCAkSkAuth, OBSAuth,
)
# Resolve the IAM endpoint for a region
auth_url = resolve_auth_url(region='eu-de')
# => 'https://iam.eu-de.otc.t-systems.com'
# Fetch credentials from metadata server
credential = metadata_config()
# => {'access': '...', 'secret': '...', 'securitytoken': '...', 'expires_at': '...'}
# Build request kwargs
kwargs = creds(token='eyJ...')
# => {'headers': {'X-Auth-Token': 'eyJ...'}}
# Or use AK/SK
kwargs = creds(ak='...', sk='...', securitytoken='...')
# => {'auth': OTCAkSkAuth(...)}
# Scope an AK/SK request to a project
add_project_id(kwargs, 'eu-de_12345')
add_domain_id(kwargs, 'OTC0000xxxx')
# Add custom headers
add_headers(kwargs, ['X-Request-Id:my-id'])
# Make the request
import requests
resp = requests.get('https://...', **kwargs)
# Issue a bearer token programmatically
token, details = login(
username='user@example.com',
password='...',
domain='OTC0000xxxx',
project='eu-de_project',
)
# token => 'eyJ...'
# details => full JSON response from IAM
# Issue temporary AK/SK from a token
creds = temp_aksk(token='eyJ...', max_secs=3600)
# => {'access': '...', 'secret': '...', 'securitytoken': '...', 'expires_at': '...'}
# Revoke a token
logout(token='eyJ...')The tcurl_login module provides an interactive urwid-based form:
from tcurl_login import CredentialForm
form = CredentialForm()
result = form.run()
# => {'username': '...', 'password': '...', 'domain': '...', 'totp': '...'}- The
--projectshort flag (-p) in thelogincommand refers to a project name, not a project ID. - When using
--projectinlogin, the region is automatically derived from the project name (the part before the first_). - All REST verb commands accept
get,post,put,patch,delete,head, andoptionsboth in lowercase (e.g.get) and uppercase (e.g.GET). - The tool supports reading arguments from a file using the
@prefix (e.g.python tcurl.py get @args.txt). - Credential resolution order for REST verbs: command-line arguments → metadata server → environment variables.
- The
--regionand--projectoptions onloginare mutually exclusive. When--projectis used, the region is derived from the project name prefix. - The
--interactivemode reads from stdin when running in a TTY, or silently from stdin when piped (useful for automation scripts). - The
tcurl-loginconsole script (urwid-based TUI) requiresurwid. It provides a dialog-style form with password masking and Tab navigation.