Quilt supports two authentication methods for accessing your data:
Interactive Login: Web-based OAuth/SSO authentication (best for notebooks, local development)
API Keys: Token-based authentication (best for automation, CI/CD, scripts)
Interactive Authentication
Interactive authentication uses OAuth or SSO to authenticate through your web browser. This is the recommended method for personal use, Jupyter notebooks, and local development.
Login
import quilt3# Opens your browser for authenticationquilt3.login()
This command will:
Open your default web browser
Redirect you to your Quilt catalog's login page
After successful authentication, save credentials locally
Return you to your Python session
Check Authentication Status
Logout
API Key Authentication
API keys provide programmatic access to Quilt without requiring browser-based authentication. Keys are created through the Python API and can be used for automated workflows.
When to Use API Keys
Use API Keys For
Automated scripts and data pipelines
Server-side applications and microservices
Containerized applications (Docker, Kubernetes)
Cloud functions and serverless workloads
CI/CD pipelines and automated workflows
Scheduled jobs and batch processing
Creating Your First API Key
Step 1: Authenticate Interactively
First, log in using the interactive method:
Step 2: Create an API Key
⚠️ Security Warning: The secret is only shown once during creation. Save it immediately in a secure location. If you lose it, you'll need to create a new key.
Step 3: Store the Secret Securely
Choose a secure storage method based on your environment:
Local Development
Create a .env file in your project directory:
Load it in your Python code:
IMPORTANT: Add .env to your .gitignore to prevent committing secrets.
For production deployments, embed it in environment variables or AWS secrets manager.
Step 4: Use the API Key
NOTE: quilt3 will not automatically detect and use the QUILT_API_KEY. You must explicitly login with it.
Managing Your API Keys
List All Your Keys
Filter Keys
Get a Specific Key
Revoke a Key
Best Practices
Security Guidelines
🔐 Never commit API keys to version control
Add .env files to .gitignore
Use secret scanning tools (GitGuardian, GitHub Advanced Security)
🔐 Use environment variables or secret managers
Never hardcode keys in source code
Prefer managed secret services in production
🔐 Rotate keys regularly
Set up rotation before expiration (60-90 days)
Plan rotation during low-traffic periods
🔐 Use descriptive names
Include purpose, environment, and date: ci-github-prod-2026q1
Makes key management and auditing easier
🔐 Revoke unused keys immediately
Delete keys when pipelines are retired
Conduct regular key audits
🔐 Use separate keys per environment
Different keys for dev, staging, production
Limits blast radius if a key is compromised
Administrator Guide
Administrators have additional capabilities to manage API keys across all users.
Prerequisites
You must be an admin user to access these functions:
# Returns catalog URL if authenticated, None otherwise
catalog_url = quilt3.logged_in()
if catalog_url:
print(f"Authenticated to: {catalog_url}")
else:
print("Not authenticated")
# Clear all credentials (both interactive and API keys)
quilt3.logout()
import quilt3
quilt3.login()
# Create a key that expires in 90 days (default)
key, secret = quilt3.api_keys.create("my-automation-key")
# Or specify a custom expiration (1-365 days)
key, secret = quilt3.api_keys.create("my-key", expires_in_days=180)
# IMPORTANT: Save the secret - it's only shown once!
print(f"Key ID: {key.id}")
print(f"Owner: {key.email}")
print(f"Secret: {secret}")
print(f"Fingerprint: {key.fingerprint}")
print(f"Expires: {key.expires_at}")
# Example output:
# Secret: qk_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z...
# .env
QUILT_API_KEY=qk_your_secret_here
from dotenv import load_dotenv
import os
load_dotenv() # Load .env file
api_key = os.environ["QUILT_API_KEY"]
import os
import quilt3
# Load from environment
api_key = os.environ["QUILT_API_KEY"]
quilt3.login_with_api_key(api_key)
# Now use Quilt normally
pkg = quilt3.Package.browse("mypackage", "s3://mybucket")
import quilt3
# List all your keys
keys = quilt3.api_keys.list()
for key in keys:
print(f"\n{key.name}")
print(f" Owner: {key.email}")
print(f" ID: {key.id}")
print(f" Fingerprint: {key.fingerprint}")
print(f" Status: {key.status}")
print(f" Created: {key.created_at}")
print(f" Expires: {key.expires_at}")
print(f" Last used: {key.last_used_at or 'Never'}")
# Find keys by name
production_keys = quilt3.api_keys.list(name="production-pipeline")
# Find keys by fingerprint
key = quilt3.api_keys.list(fingerprint="qk_abc...xyz")
# Find only active keys
active_keys = quilt3.api_keys.list(status="ACTIVE")
# Find expired keys
expired_keys = quilt3.api_keys.list(status="EXPIRED")
# Get details about a specific key
key = quilt3.api_keys.get("key-id-here")
if key:
print(f"Name: {key.name}")
print(f"Owner: {key.email}")
print(f"Status: {key.status}")
if key.status == "EXPIRED":
print("This key has expired and needs to be rotated")
else:
print("Key not found")
# Revoke by ID (if you know it)
quilt3.api_keys.revoke(id="key-id-here")
# Or revoke by secret (useful for immediate emergency revocation)
quilt3.api_keys.revoke(secret="qk_your_secret")
import quilt3.admin
# List all keys in the system
all_keys = quilt3.admin.api_keys.list()
print(f"Total keys: {len(all_keys)}")
# Filter by user email
user_keys = quilt3.admin.api_keys.list(email="[email protected]")
print(f"Keys for [email protected]: {len(user_keys)}")
# Filter by key name
pipeline_keys = quilt3.admin.api_keys.list(key_name="ci-pipeline")
# Filter by status
active_keys = quilt3.admin.api_keys.list(status="ACTIVE")
expired_keys = quilt3.admin.api_keys.list(status="EXPIRED")
print(f"Active keys: {len(active_keys)}")
print(f"Expired keys: {len(expired_keys)}")
# Get details about a specific key
key = quilt3.admin.api_keys.get("key-id-here")
if key:
print(f"Key: {key.name}")
print(f"Owner: {key.user_email}")
print(f"ID: {key.id}")
print(f"Status: {key.status}")
print(f"Created: {key.created_at}")
print(f"Expires: {key.expires_at}")
print(f"Last used: {key.last_used_at or 'Never'}")
# Revoke a specific key by ID
key_id = "key-id-here"
quilt3.admin.api_keys.revoke(id=key_id)
print(f"Revoked key: {key_id}")
from datetime import datetime, timedelta
# Find keys that haven't been used in 90 days
threshold = datetime.now() - timedelta(days=90)
all_keys = quilt3.admin.api_keys.list(status="ACTIVE")
unused_keys = []
for key in all_keys:
if key.last_used_at is None or key.last_used_at < threshold:
unused_keys.append(key)
print(f"⚠️ Unused key: {key.name}")
print(f" Owner: {key.user_email}")
print(f" ID: {key.id}")
print(f" Last used: {key.last_used_at or 'Never'}")
print(f"\nFound {len(unused_keys)} unused keys")
# Get summary statistics
all_keys = quilt3.admin.api_keys.list()
active = sum(1 for k in all_keys if k.status == "ACTIVE")
expired = sum(1 for k in all_keys if k.status == "EXPIRED")
print("API Key Usage Report")
print("=" * 60)
print(f"Total keys: {len(all_keys)}")
print(f"Active: {active}")
print(f"Expired: {expired}")
# Show recent keys
print("\nRecently created keys:")
sorted_keys = sorted(all_keys, key=lambda k: k.created_at, reverse=True)
for key in sorted_keys[:10]:
print(f" {key.name}")
print(f" Created: {key.created_at}")
print(f" Status: {key.status}")
print(f" Owner: {key.user_email}")
SELECT
eventtime,
eventname,
json_extract_scalar(useridentity, '$.email') as user_email,
json_extract_scalar(useridentity, '$.sessionContext.auth.keyName') as key_name,
json_extract_scalar(useridentity, '$.sessionContext.auth.keyFingerprint') as key_fingerprint,
sourceipaddress
FROM audit_trail
WHERE date >= date_format(current_date - interval '30' day, '%Y/%m/%d')
AND json_extract_scalar(useridentity, '$.sessionContext.auth.type') = 'api_key'
ORDER BY eventtime DESC
LIMIT 100;
api_key = "qk_..." # Must start with qk_
if not api_key.startswith("qk_"):
print("Invalid key format!")
import quilt3
quilt3.login() # Use interactive login first
keys = quilt3.api_keys.list()
for key in keys:
print(f"{key.name}: {key.status}")
import quilt3
quilt3.logout() # Clear all credentials
quilt3.login_with_api_key(api_key) # Try again
import quilt3
# Check expiration
quilt3.login()
keys = quilt3.api_keys.list(name="my-key")
for key in keys:
print(f"Status: {key.status}")
print(f"Expires: {key.expires_at}")
# Create new key
new_key, secret = quilt3.api_keys.create("my-key-v2", expires_in_days=90)
print(f"New secret: {secret}")
# Revoke old key
quilt3.api_keys.revoke(id=keys[0].id)
import os
print(os.environ.get("QUILT_API_KEY")) # Should show qk_...
import quilt3
# Requires browser - doesn't work in CI/CD
quilt3.login()
pkg = quilt3.Package.browse("data/latest", "s3://mybucket")
import os
import quilt3
# One-time setup: Create API key
# (Run this once on your local machine)
# quilt3.login()
# key, secret = quilt3.api_keys.create("my-script")
# print(f"Secret: {secret}")
# In your script: Use the API key
api_key = os.environ.get("QUILT_API_KEY")
if not api_key:
raise ValueError("QUILT_API_KEY environment variable required")
quilt3.login_with_api_key(api_key)
pkg = quilt3.Package.browse("data/latest", "s3://mybucket")