Skip to content

OAuth Token Handling

OAuth token lifecycle and security considerations.


Overview

Dango uses OAuth for sources that require user authorization:

  • Google Sheets
  • Google Analytics (GA4)
  • Facebook Ads
  • Google Ads

How OAuth Works in Dango

Authentication Flow

1. You run: dango oauth google_sheets

2. Browser opens to Google login

3. You authorize Dango to access your data

4. Google returns tokens to Dango

5. Tokens stored securely in secrets.toml

Token Types

Token Purpose Lifetime
Access Token API requests 1 hour
Refresh Token Get new access tokens Long-lived*

*Refresh tokens can expire if unused for extended periods or if revoked.


Token Storage

Location

OAuth tokens are stored in .dlt/secrets.toml under the source credentials section:

# .dlt/secrets.toml
[sources.google_sheets.credentials]
client_id = "xxx.apps.googleusercontent.com"
client_secret = "xxx"
refresh_token = "1//xxx"

Encryption Key Storage

The system keyring (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows) stores only an encryption key used to protect sensitive tokens - not the tokens themselves.

What's Stored

The secrets.toml file contains:

  • OAuth credentials: client_id, client_secret, refresh_token
  • Access tokens: Short-lived tokens refreshed automatically
  • Metadata: Token expiry timestamps, scopes granted

Token Lifecycle

Initial Authentication

# Authenticate with Google Sheets
dango oauth google_sheets
  1. Opens browser to Google consent screen
  2. You approve access
  3. Tokens saved to .dlt/secrets.toml

Token Refresh

Dango automatically refreshes expired access tokens:

Sync starts
├── Check access token
├── Token expired?
│   ├── Yes: Use refresh token to get new access token
│   └── No: Use existing access token
└── Make API request

No manual intervention needed for routine refresh.

Token Expiry

Access tokens: Expire after ~1 hour - Refreshed automatically

Refresh tokens: Can expire due to: - 6+ months of inactivity - User revokes access - Password change (some providers) - Reaching token limit

When refresh token expires:

# Re-authenticate
dango oauth google_sheets


Managing OAuth Tokens

Check Token Status

# List all authenticated providers
dango oauth list

# Check OAuth credential status (shows all credentials)
dango oauth status

Example output:

OAuth Credentials Status:

  google_sheets_123456789
    Status: Valid
    Expires: 2026-06-15 10:30:00

Refresh Manually

# Force token refresh (use credential name from auth list)
dango oauth refresh google_sheets_123456789

Remove Authorization

# Remove stored tokens (use source type)
dango oauth remove google_sheets

This removes local tokens but doesn't revoke access at the provider. To fully revoke:

  1. Remove from Dango: dango oauth remove <source_type>
  2. Revoke in provider settings (see below)

Revoking Access

Google

  1. Go to Google Account Security
  2. Find "Dango" in third-party access
  3. Click "Remove Access"

Facebook

  1. Go to Facebook Settings > Apps
  2. Find "Dango"
  3. Click "Remove"

Why Revoke?

Revoke access when: - No longer using Dango - Credential rotation policy - Suspected compromise - Employee offboarding


Scopes and Permissions

What Scopes Mean

OAuth scopes define what Dango can access:

Provider Scope Access
Google Sheets spreadsheets.readonly Read spreadsheets
Google Analytics analytics.readonly Read analytics data
Facebook Ads ads_read Read ad performance

Minimal Permissions

Dango requests only the minimum scopes needed:

✓ Read spreadsheet data
✗ Edit spreadsheets
✗ Delete spreadsheets
✗ Access other Google services

Multi-Account Handling

Same Provider, Multiple Sources

OAuth credentials are shared per source type. Multiple sources of the same type use the same OAuth credentials:

# .dango/sources.yml
sources:
  - name: sheets_personal
    type: google_sheets
    google_sheets:
      spreadsheet_url_or_id: "xxx"

  - name: sheets_work
    type: google_sheets
    google_sheets:
      spreadsheet_url_or_id: "yyy"

Authenticate once for all Google Sheets sources:

dango oauth google_sheets

Both sources will use the same OAuth credentials.

Switching Accounts

# Remove current auth
dango oauth remove google_sheets

# Re-authenticate with different account
dango oauth google_sheets
# Login with different Google account when browser opens

Security Considerations

Token Security

Protect your tokens: - Tokens grant access to your data - Treat like passwords - Don't share tokens

Dango protections: - Tokens stored in secrets.toml (optionally encrypted) - Tokens never logged - Tokens never displayed in UI

When authenticating, you may see warnings:

"This app hasn't been verified by Google"

This is normal for development OAuth apps. Dango uses unverified OAuth credentials for simplicity. Click "Advanced" → "Go to Dango" to proceed.

OAuth App Security

Dango's OAuth clients: - Request minimal scopes - Don't store data externally - Tokens stay on your machine


Troubleshooting

"Invalid Grant" Error

Cause: Refresh token expired or revoked

Solution:

dango oauth remove google_sheets
dango oauth google_sheets

"Access Denied" Error

Causes: - Insufficient permissions - App not authorized for account type - Organization restrictions

Solutions: 1. Check you're logged into correct account 2. For Google Workspace: Ask admin to allow app 3. Try with personal account

Browser Doesn't Open

Manual auth:

dango oauth google_sheets
# If browser doesn't open, copy the URL from terminal
# Paste in browser manually

Token Not Saving

Check keyring:

# Verify keyring is working
python -c "import keyring; keyring.set_password('test', 'test', 'test'); print(keyring.get_password('test', 'test'))"

If keyring isn't working, install a backend:

pip install keyrings.alt


Provider Token Details

Token Expiry by Provider

Provider Access Token Refresh Token Auto-Refresh Re-auth Trigger
Google (Sheets, GA4, Ads) 1 hour No expiry (revocable) Yes (dlt) Revocation, password change, 6 months unused
Facebook Ads 1 hour 60 days (long-lived) No Must re-auth before 60-day expiry
GitHub No expiry (PAT) N/A N/A Manual revocation only

Google

  • Refresh tokens have no fixed expiry but can be revoked
  • Tokens become invalid after 6 months of inactivity
  • Re-auth required after Google password change
  • Google Workspace accounts may need admin approval for the OAuth app

Facebook

  • Long-lived tokens expire after 60 days — set a calendar reminder
  • Business accounts require Business Manager access
  • App must have ads_read permission

GitHub

  • Uses personal access tokens (PATs), not OAuth refresh tokens
  • PATs have no automatic expiry (unless configured in GitHub settings)
  • Revocation is manual via GitHub Settings → Developer Settings → Personal Access Tokens

Prevent Sync Failures

Set calendar reminders to re-authenticate Facebook OAuth sources every 45 days (before the 60-day expiry). Google sources with dlt auto-refresh rarely need manual re-auth.


Next Steps