Skip to main content

Overview

Monzoh uses OAuth2 for authentication with the Monzo API. This guide walks you through setting up OAuth2 credentials and completing the authentication flow.

Prerequisites

  • A Monzo account (personal or business)
  • A registered OAuth2 application in the Monzo Developer Portal

Setting Up OAuth2

1. Create a Developer Application

  1. Visit the Monzo Developer Portal
  2. Sign in with your Monzo account
  3. Click “Create New Application”
  4. Fill in your application details:
    • Name: Your application name
    • Description: Brief description of your app
    • Redirect URI: http://localhost:8080/callback (for local development)
    • Logo: Optional application logo
For production applications, use a proper HTTPS redirect URI pointing to your application’s callback endpoint.

2. Configure Environment Variables

Create a .env file in your project root with your OAuth2 credentials:
# Required OAuth2 credentials
MONZO_CLIENT_ID=your_client_id_here
MONZO_CLIENT_SECRET=your_client_secret_here
MONZO_REDIRECT_URI=http://localhost:8080/callback

# Optional: Custom base URL (defaults to https://api.monzo.com)
MONZO_BASE_URL=https://api.monzo.com
Alternatively, you can set these as environment variables:
export MONZO_CLIENT_ID="your_client_id_here"
export MONZO_CLIENT_SECRET="your_client_secret_here"
export MONZO_REDIRECT_URI="http://localhost:8080/callback"

Authentication Flow

Command Line Authentication

The simplest way to authenticate is using the built-in CLI tool:
monzoh-auth
This command will:
  1. Start a local web server on port 8080
  2. Open your default browser to the Monzo authorization page
  3. Handle the OAuth2 callback automatically
  4. Save your access and refresh tokens securely
Tokens are saved in your system’s cache directory:
  • macOS: ~/Library/Caches/monzoh/tokens.json
  • Windows: %LOCALAPPDATA%/monzoh/tokens.json
  • Linux: ~/.cache/monzoh/tokens.json

Programmatic Authentication

For more control, you can handle the OAuth2 flow programmatically:
from monzoh import MonzoOAuth

# Initialize OAuth handler
oauth = MonzoOAuth()

# Get authorization URL
auth_url = oauth.get_authorization_url()
print(f"Visit this URL to authorize: {auth_url}")

# After user authorizes, exchange the code for tokens
# (You'll receive this code via your redirect URI)
authorization_code = "received_from_callback"
tokens = oauth.exchange_code_for_tokens(authorization_code)

print(f"Access token: {tokens.access_token}")
print(f"Refresh token: {tokens.refresh_token}")

Custom Redirect URI

If you’re building a web application, you can use a custom redirect URI:
from monzoh import MonzoOAuth

oauth = MonzoOAuth(
    client_id="your_client_id",
    client_secret="your_client_secret",
    redirect_uri="https://your-app.com/auth/callback"
)

# Generate authorization URL
auth_url = oauth.get_authorization_url(
    state="random_state_string"  # Optional state parameter for CSRF protection
)

# Redirect user to auth_url...
# Handle callback at your redirect URI...

Token Management

Automatic Token Refresh

Monzoh automatically refreshes expired access tokens using the stored refresh token:
from monzoh import MonzoClient

# Client will automatically refresh tokens when needed
client = MonzoClient()

# This call will work even if the access token has expired
accounts = client.accounts.list()

Manual Token Management

You can also manage tokens manually:
from monzoh import MonzoOAuth, OAuthToken

# Load existing tokens
oauth = MonzoOAuth()
tokens = oauth.load_tokens()

if tokens and oauth.is_token_expired(tokens):
    # Refresh expired token
    new_tokens = oauth.refresh_token(tokens.refresh_token)
    oauth.save_tokens(new_tokens)
    print("Token refreshed successfully")

# Use tokens with client
client = MonzoClient(access_token=tokens.access_token)

Token Storage Locations

Tokens are stored in different locations based on your operating system:
  • macOS
  • Windows
  • Linux
~/Library/Caches/monzoh/tokens.json

Client Initialization

Default Initialization

The simplest way to create a client is using stored tokens:
from monzoh import MonzoClient

# Uses tokens from default storage location
client = MonzoClient()

Custom Access Token

You can provide an access token directly:
from monzoh import MonzoClient

client = MonzoClient(access_token="your_access_token_here")

Custom HTTP Client

For advanced use cases, you can provide a custom HTTP client:
import httpx
from monzoh import MonzoClient

# Custom HTTP client with timeout and retries
http_client = httpx.Client(
    timeout=60.0,
    limits=httpx.Limits(max_connections=10)
)

client = MonzoClient(
    access_token="your_token",
    http_client=http_client
)

Testing Authentication

Check Authentication Status

from monzoh import MonzoClient, MonzoAuthenticationError

client = MonzoClient()

try:
    whoami = client.whoami()
    print(f"✅ Authenticated as user: {whoami.user_id}")
    print(f"Client ID: {whoami.client_id}")
    print(f"Authenticated: {whoami.authenticated}")
except MonzoAuthenticationError as e:
    print(f"❌ Authentication failed: {e}")
    print("Run 'monzoh-auth' to authenticate")

Validate Token Permissions

from monzoh import MonzoClient

client = MonzoClient()

# Check what you can access
try:
    accounts = client.accounts.list()
    print(f"✅ Can access {len(accounts)} accounts")
    
    if accounts:
        balance = client.accounts.get_balance(account_id=accounts[0].id)
        print(f"✅ Can read account balance")
        
        transactions = client.transactions.list(account_id=accounts[0].id, limit=1)
        print(f"✅ Can read transactions")
        
except Exception as e:
    print(f"❌ Permission error: {e}")

Security Best Practices

Always store credentials in environment variables or secure configuration files, never in source code.
# ✅ Good
client_id = os.getenv("MONZO_CLIENT_ID")

# ❌ Bad
client_id = "oauth2_client_1234567890abcdef"
Monzoh stores tokens in your system’s secure cache directory. For production applications, consider using a secure token store.
# Custom secure token storage
from monzoh import MonzoOAuth

class SecureTokenStore:
    def save_tokens(self, tokens):
        # Save to secure store (database, vault, etc.)
        pass
        
    def load_tokens(self):
        # Load from secure store
        pass
Always use HTTPS redirect URIs in production to prevent token interception.
# ✅ Production
redirect_uri = "https://your-app.com/auth/callback"

# ⚠️ Development only
redirect_uri = "http://localhost:8080/callback"
Use the state parameter to prevent CSRF attacks in web applications.
import secrets

state = secrets.token_urlsafe(32)
auth_url = oauth.get_authorization_url(state=state)

# Verify state in callback
if callback_state != stored_state:
    raise SecurityError("Invalid state parameter")

Troubleshooting

Error: MonzoAuthenticationError: Invalid access tokenSolutions:
  • Run monzoh-auth to re-authenticate
  • Check that your OAuth2 credentials are correct
  • Verify that your access token hasn’t been revoked
Error: invalid_request: redirect_uri mismatchSolutions:
  • Ensure the redirect URI matches exactly with your OAuth2 app settings
  • Check for trailing slashes or protocol mismatches
  • Update your app settings in the Monzo Developer Portal
Error: Address already in use: 8080Solutions:
  • Use a different port: monzoh-auth --port 8081
  • Kill any processes using port 8080
  • Update your OAuth2 app’s redirect URI to match the new port
Error: FileNotFoundError: tokens.json not foundSolutions:
  • Run monzoh-auth to create initial tokens
  • Check file permissions on the cache directory
  • Manually specify token location if needed

Next Steps

Now that you’re authenticated, you can start making API calls:
I