Backup & Restore

Authagonal provides two CLI tools for backing up and restoring Azure Table Storage data. Both are .NET console applications in the tools/ directory.

Backup

dotnet run --project tools/Authagonal.Backup -- \
  --connection-string "DefaultEndpointsProtocol=https;..." \
  --output ./backups

Options

Option Description
--connection-string <conn> Azure Table Storage connection string (or set STORAGE_CONNECTION_STRING env var)
--output <dir> Output directory (default: ./backups)
--incremental Only back up entities changed since last backup
--tables <t1,t2,...> Comma-separated list of tables (default: all Authagonal tables)
--gzip Compress backup files with gzip (.jsonl.gz)
--dry-run Show what would be backed up without writing

Output format

Each backup creates a timestamped directory:

backups/
  20260329-120000/          (full backup)
    Users.jsonl
    Clients.jsonl
    Grants.jsonl
    ...
    _manifest.json
  20260329-180000-incr/     (incremental, compressed)
    Users.jsonl.gz
    _manifest.json

Each .jsonl file contains one JSON object per line (one per table entity). With --gzip, files are compressed as .jsonl.gz. The _manifest.json records the backup timestamp, mode, compression, entity counts, and SHA-256 file hashes for integrity verification.

Integrity verification

Each backup manifest includes a FileHashes dictionary mapping filenames to their SHA-256 hashes. During restore, file integrity is automatically verified against these hashes before any data is written. If a hash mismatch is detected, the restore aborts with an error.

Incremental backups

Pass --incremental to only back up entities modified since the last successful backup. The tool uses Azure Table Storage’s built-in Timestamp property for filtering and tracks the high-water mark in a .lastbackup file in the output directory.

If no .lastbackup file exists, the first incremental run performs a full backup.

Default tables

The backup tool includes all Authagonal tables by default:

Users, UserEmails, UserLogins, UserExternalIds, Clients, Grants, GrantsBySubject, GrantsByExpiry, SigningKeys, SsoDomains, SamlProviders, OidcProviders, UserProvisions, MfaCredentials, MfaChallenges, MfaWebAuthnIndex, ScimTokens, ScimGroups, ScimGroupExternalIds, Roles

Transient tables (SamlReplayCache, OidcStateStore) are excluded by default — include them explicitly with --tables if needed.

Restore

dotnet run --project tools/Authagonal.Restore -- \
  --connection-string "DefaultEndpointsProtocol=https;..." \
  --input ./backups/20260329-120000

Options

Option Description
--connection-string <conn> Azure Table Storage connection string (or set STORAGE_CONNECTION_STRING env var)
--input <dir> Backup directory to restore from
--mode <mode> Restore mode: upsert (default), merge, or clean
--tables <t1,t2,...> Comma-separated list of tables to restore (default: all .jsonl/.jsonl.gz files in backup)
--dry-run Show what would be restored without writing

Restore modes

Mode Behaviour
upsert Insert or replace each entity. Existing data is overwritten.
merge Insert or merge. Existing properties not in the backup are preserved.
clean Delete all existing data in each table before restoring.

Gzip-compressed backup files (.jsonl.gz) are detected and decompressed automatically — no extra flags needed.

Exit codes

Code Meaning
0 Success
1 Error (missing arguments, invalid input)
2 Partial success (some entities had errors)

Docker

Both tools have Docker images for running in CI or without installing the .NET SDK:

# Backup
docker run --rm -v $(pwd)/backups:/backups \
  -e STORAGE_CONNECTION_STRING="..." \
  drawboardci/authagonal-backup --output /backups

# Restore
docker run --rm -v $(pwd)/backups:/backups \
  -e STORAGE_CONNECTION_STRING="..." \
  drawboardci/authagonal-restore --input /backups/20260329-120000

Scheduling backups

For production use, run the backup tool on a schedule (e.g. daily full + hourly incremental):

# Daily full backup (compressed)
0 2 * * * authagonal-backup --connection-string "$CONN" --output /backups --gzip

# Hourly incremental (compressed)
0 * * * * authagonal-backup --connection-string "$CONN" --output /backups --incremental --gzip