Access Tokens¶
Access tokens are short-lived credentials that grant a script or integration the right to read or write to a specific site's REST API. They are entirely separate from your personal ECMWF password and can be revoked at any time.
Why use access tokens?¶
- Automation: Scripts and pipelines can authenticate without storing your personal credentials.
- Scoped access: Tokens can be read-only (
Read) or read-write (ReadWrite). - Auditable: Each token has an
identifierlabel, so you can track which script used which token. - Time-limited: Tokens expire after the duration you choose, reducing exposure if one leaks.
Concepts¶
| Concept | Meaning |
|---|---|
| Identifier | A free-text label you choose, used for audit purposes (e.g., 'backup-script', 'ci-pipeline') |
| Duration | How long the token is valid, in seconds |
| Permission | Read (download only) or ReadWrite (upload, download, delete) |
| Token hash | A SHA256 fingerprint of the token. Use this to revoke or delete history entries without exposing the token string itself |
SiteAccessPermission values:
from sites.sdk.sites.utils import SiteAccessPermission
SiteAccessPermission.Read # read-only access to the site
SiteAccessPermission.ReadWrite # read and write access
Getting a content manager¶
All token operations are performed through a SiteContentManagement instance. You need to authenticate as someone with administration rights over the site.
from sites.sdk.sites import Site, Authenticator
site = Site.from_space_and_name(space='docs', name='my-project')
# Use the site's unique bearer token OR hub credentials with admin rights
content_manager = site.get_content_manager(
authenticator=Authenticator.from_token(token='<admin_site_bearer_token>')
)
Generating a token¶
from sites.sdk.sites.utils import SiteAccessPermission
token_data = content_manager.generate_token(
identifier='my-backup-script', # label for audit trail
duration=86400, # valid for 1 day (86400 seconds)
permission=SiteAccessPermission.Read
)
print(token_data['data']['token'])
# abc123def456...
# Save this token and use it with Authenticator.from_token()
Common duration values:
| Duration (seconds) | Human-readable |
|---|---|
3600 |
1 hour |
86400 |
1 day |
604800 |
7 days |
2592000 |
30 days |
Using a generated token¶
Pass the token to Authenticator.from_token to authenticate as the site:
from sites.sdk.sites import Authenticator
site_auth = Authenticator.from_token(token='abc123def456...')
worker_content_manager = site.get_content_manager(authenticator=site_auth)
# This content manager now uses the scoped token, not your personal credentials
worker_content_manager.download(remote_path='data.csv')
Decoding / inspecting a token¶
To check what a token contains (identifier, permission, and expiry) without revoking it:
token_info = content_manager.decode_token(token='abc123def456...')
print(token_info)
# {'data': {'identifier': 'my-backup-script', 'permission': 'r', 'expiry': '2026-03-17T10:00:00'}, 'status': 'OK'}
Revoking a token¶
Revoking a token immediately invalidates it. Provide either the token string or its SHA256 hash — not both.
Revoke by token string:
Revoke by hash (preferred — avoids passing the raw token around):
result = content_manager.revoke_token(token_hash='e3b0c44298fc1c149afbf...')
print(result['message'])
Viewing token history¶
Token history records when each identifier+permission pair was most recently used. This is useful for auditing which scripts are actively accessing your site.
List all token history¶
Filter token history¶
from sites.sdk.sites.utils import SiteAccessPermission
# All entries for a specific identifier
history = content_manager.token_history(identifier='my-backup-script')
# Only read-write tokens
history = content_manager.token_history(permission=SiteAccessPermission.ReadWrite)
# Tokens expiring within the next 7 days
history = content_manager.token_history(expiring_within=604800)
# Include already-expired tokens (they are hidden by default)
history = content_manager.token_history(include_expired=True)
Combine filters freely:
history = content_manager.token_history(
identifier='ci-pipeline',
permission=SiteAccessPermission.ReadWrite,
include_expired=False
)
Deleting a token history entry¶
Deletes a single history row identified by its SHA256 hash. This does not revoke the token itself — it only removes the history record.
result = content_manager.delete_token_history(
token_hash='e3b0c44298fc1c149afbf4c8996fb924...'
)
print(result['message'])
Backing up token history¶
Creates a gzipped JSON backup of all token history entries stored on the server. The backup is kept server-side.
backup = content_manager.backup_token_history()
print(backup['data'])
# {'timestamp': '2026-03-16T15:30:00', 'row_count': 42, 'checksum': 'sha256...'}
Restoring token history¶
Restores the token history from the latest backup. This is a destructive operation — all current history entries are deleted and replaced with the backup data.
Warning: Restoring replaces the entire current history. Use with caution.
End-to-end example: token lifecycle¶
from sites.sdk.sites import Site, Authenticator
from sites.sdk.sites.utils import SiteAccessPermission
site = Site.from_space_and_name(space='docs', name='my-project')
admin_auth = Authenticator.from_token(token='<admin_site_bearer_token>')
mgr = site.get_content_manager(authenticator=admin_auth)
# 1. Generate a read-only token for a pipeline
token_data = mgr.generate_token(
identifier='ci-pipeline',
duration=2592000, # 30 days
permission=SiteAccessPermission.Read
)
token = token_data['data']['token']
print('Token:', token)
# 2. Inspect it
info = mgr.decode_token(token=token)
print('Expires:', info['data']['expiry'])
# 3. The pipeline uses it to download data (e.g., a build artifact)
pipeline_auth = Authenticator.from_token(token=token)
pipeline_mgr = site.get_content_manager(authenticator=pipeline_auth)
content = pipeline_mgr.download(remote_path='artefacts/build.zip')
# 4. After the pipeline run, audit who accessed what
history = mgr.token_history(identifier='ci-pipeline')
print(history)
# 5. When no longer needed, revoke it
mgr.revoke_token(token=token)
What's next?¶
- Signed URLs — create time-limited shareable links for individual files
- Authentication — using access tokens with
Authenticator.from_token - API Reference — quick method reference