Back to Articles

Authomatic: The Framework-Agnostic Python Authentication Library You've Probably Never Heard Of

[ View on GitHub ]

Authomatic: The Framework-Agnostic Python Authentication Library You’ve Probably Never Heard Of

Hook

While Django developers flock to django-allauth and Flask users swear by Flask-Login, there’s a Python authentication library that works identically across all major frameworks—yet fewer than 1,100 developers have starred it.

Context

Python’s web framework ecosystem has always been fragmented. If you’ve built authentication for a Django app, that code is useless when your next project uses Flask or Pyramid. Each framework has its own request/response objects, session handling, and middleware patterns. This fragmentation led to framework-specific authentication libraries: django-allauth for Django, Flask-Login for Flask, and so on. The problem intensifies when integrating OAuth providers—each provider has subtle differences in their flows, error handling, and token management.

Authomatic emerged to solve this dual problem: framework fragmentation and provider inconsistency. Created as a unified authentication layer, it abstracts both the framework details and the OAuth protocol variations behind a single API. Whether you’re authenticating with Google OAuth 2.0 in a Pyramid app or Facebook OAuth in a Webapp2 application, the code looks nearly identical. This made Authomatic particularly valuable for teams maintaining multiple Python web applications or building authentication microservices that need to work across different frameworks.

Technical Insight

Authomatic Core

Web Framework Layer

1. Login Request
2. Translate Request
3. Initiate Flow
4. Select Provider
5. Redirect
6. Auth Code
7. Token Exchange
8. Access Token
9. Fetch User Info
10. User Data
11. Result Object
12. Framework Response

Client Browser

Flask/Django/Pyramid

Framework Adapter

Authentication Core

OAuth2 Provider

OAuth Server

Google/GitHub/etc

System architecture — auto-generated

Authomatic’s architecture centers on two key abstractions: adapters and providers. The adapter pattern decouples authentication logic from framework-specific request/response handling. Each framework adapter implements the same interface, translating between Authomatic’s internal representation and the framework’s native objects.

Here’s how you’d implement Google OAuth authentication in Flask versus Django:

# Flask implementation
from authomatic import Authomatic
from authomatic.adapters import WerkzeugAdapter
from flask import Flask, request, make_response

app = Flask(__name__)

authomatic = Authomatic(
    config={
        'google': {
            'class_': 'authomatic.providers.oauth2.Google',
            'consumer_key': 'YOUR_CLIENT_ID',
            'consumer_secret': 'YOUR_CLIENT_SECRET',
            'scope': ['profile', 'email'],
        }
    },
    secret='random-secret-string'
)

@app.route('/login/<provider_name>')
def login(provider_name):
    response = make_response()
    result = authomatic.login(WerkzeugAdapter(request, response), provider_name)
    
    if result:
        if result.user:
            result.user.update()  # Fetch user info
            return f'Logged in as {result.user.name}'
    
    return response

# Django implementation - nearly identical
from authomatic.adapters import DjangoAdapter
from django.http import HttpResponse

def login(request, provider_name):
    response = HttpResponse()
    result = authomatic.login(DjangoAdapter(request, response), provider_name)
    
    if result:
        if result.user:
            result.user.update()
            return HttpResponse(f'Logged in as {result.user.name}')
    
    return response

Notice how only the adapter changes—WerkzeugAdapter for Flask, DjangoAdapter for Django. The authentication logic remains identical. This is powerful for microservice architectures where different services might use different frameworks but need consistent authentication.

The provider abstraction layer handles protocol differences internally. When you call authomatic.login(), it orchestrates a multi-step flow: constructing authorization URLs with proper parameters, handling OAuth callbacks, exchanging authorization codes for access tokens, and making authenticated API calls to fetch user data. Each provider class inherits from base OAuth1 or OAuth2 classes that implement the protocol mechanics, while provider-specific subclasses handle quirks like non-standard token endpoints or custom scopes.

Version 2.0, completed as part of Google Summer of Code 2025, represents a significant architectural shift. The team removed OAuth 1.0a support entirely, eliminating thousands of lines of legacy code. They migrated providers like Bitbucket, Vimeo, and Tumblr from OAuth 1.0a to OAuth 2.0 implementations. The test suite now uses pytest-httpx to mock HTTP interactions, creating realistic fixtures that capture actual provider response patterns:

# Example of v2.0's testing approach
import pytest
from pytest_httpx import HTTPXMock

def test_google_oauth_flow(httpx_mock: HTTPXMock):
    # Mock token exchange
    httpx_mock.add_response(
        url='https://oauth2.googleapis.com/token',
        json={
            'access_token': 'ya29.test_token',
            'expires_in': 3600,
            'token_type': 'Bearer'
        }
    )
    
    # Mock user info request
    httpx_mock.add_response(
        url='https://www.googleapis.com/oauth2/v2/userinfo',
        json={
            'id': '12345',
            'email': 'user@example.com',
            'name': 'Test User'
        }
    )
    
    # Test authentication flow
    result = authomatic.login(adapter, 'google')
    assert result.user.email == 'user@example.com'

This testing approach makes provider implementations more maintainable and catches breaking changes when OAuth providers update their APIs. The migration to Python 3.10+ also enabled use of modern type hints and pattern matching, making the codebase more maintainable for future contributors.

One often-overlooked feature is Authomatic’s credential storage mechanism. It serializes OAuth tokens and user data into session storage automatically, but provides hooks for custom storage backends. This makes it straightforward to store tokens in Redis, databases, or encrypted cookies without rewriting authentication logic.

Gotcha

The version 2.0 upgrade creates a hard compatibility break if you’re using OAuth 1.0a providers. Twitter’s v1.1 API, Flickr, Tumblr (pre-migration), Bitbucket (pre-migration), Vimeo, Discogs, and several other services relied on OAuth 1.0a implementations that no longer exist in the codebase. If your application authenticates against these legacy APIs, you’re stuck on Authomatic 1.x indefinitely or need to rewrite your authentication layer entirely. The migration guide doesn’t provide a clear path forward for these scenarios—you’re expected to either upgrade to provider’s OAuth 2.0 APIs (when available) or switch libraries.

The Python 3.10+ requirement also creates deployment challenges. If you’re maintaining applications on Ubuntu 20.04 LTS (which ships with Python 3.8) or enterprise environments with standardized Python 3.8/3.9 runtimes, you can’t use Authomatic 2.0 without containerization or custom Python builds. The library also shows signs of limited maintenance velocity—the 1,051 GitHub stars suggest moderate adoption, and most development happens through volunteer contributions rather than dedicated maintainers. When OAuth providers change their APIs (which happens frequently), you might wait months for compatibility updates. The documentation, while comprehensive for supported providers, lacks examples for edge cases like handling token refresh with short-lived tokens or implementing custom OAuth flows for enterprise identity providers.

Verdict

Use if: You’re building authentication that must work across multiple Python web frameworks (especially if you’re using Pyramid or Webapp2 where alternatives are limited), need a consistent API for integrating 20+ OAuth providers without learning each provider’s quirks, or are starting a new project on Python 3.10+ that only needs OAuth 2.0 support. It’s particularly valuable for microservice architectures where services use different frameworks but share authentication logic. Skip if: You need OAuth 1.0a support, are locked to Python versions below 3.10, require enterprise-grade support with SLAs, are building a Django-only application (django-allauth offers deeper framework integration and more active maintenance), need bleeding-edge provider support (Authlib updates faster), or are building production systems where authentication library maintenance velocity is critical—the volunteer-driven development model creates uncertainty for long-term support.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/automation/authomatic-authomatic.svg)](https://starlog.is/api/badge-click/automation/authomatic-authomatic)