Flaxon OAuth Google
Google OAuth 2.0 authentication plugin for Flaxon framework.
Table of Contents
Features
- 🔐 OAuth 2.0 Authorization Code Flow — Full OAuth 2.0 implementation
- 👤 User Info Retrieval — Fetch user profile from Google's API
- 🔄 Session Management — Optional session creation after authentication
- 🛡️ CSRF Protection — State parameter validation
- ⚙️ Configurable Scopes — Request only the permissions you need
- 🧩 User Mapping — Map Google user data to your app's user model
- 🎯 Error Handling — Graceful OAuth error handling
- 🔁 Refresh Tokens — Automatic token refresh support
Installation
pip install flaxon-oauth-google
Quick Start
from flaxon import Flaxon
from flaxon_oauth_google import GoogleOAuthPlugin
app = Flaxon("my-app")
# Basic usage with environment variables
app.plugins.load_plugin(GoogleOAuthPlugin(
client_id="your-client-id.apps.googleusercontent.com",
client_secret="your-client-secret",
redirect_uri="https://yourapp.com/auth/google/callback",
))
@app.get("/")
async def home(request):
return """
<a href="/auth/google/login">Sign in with Google</a>
"""
Configuration
Environment Variables
# Required
export GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
export GOOGLE_CLIENT_SECRET=your-client-secret
# Optional
export GOOGLE_REDIRECT_URI=https://yourapp.com/auth/google/callback
export GOOGLE_SCOPES=openid,email,profile
export GOOGLE_SUCCESS_REDIRECT=/dashboard
export GOOGLE_FAILURE_REDIRECT=/login?error=oauth_failed
With Flaxon Config
app = Flaxon("my-app", config={
"GOOGLE_CLIENT_ID": "your-client-id",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"GOOGLE_REDIRECT_URI": "https://yourapp.com/auth/google/callback",
})
plugin = GoogleOAuthPlugin.from_config(app.config)
app.plugins.load_plugin(plugin)
Advanced Usage
Custom Session Creation
def create_session_from_user(google_user):
"""Create a session from Google user data."""
user = app_user_from_google(google_user)
session_token = generate_session_token(user)
return session_token
plugin = GoogleOAuthPlugin(
client_id="...",
client_secret="...",
redirect_uri="...",
session_maker=create_session_from_user,
success_redirect="/dashboard",
)
app.plugins.load_plugin(plugin)
Custom User Mapping
def map_google_user(google_user):
"""Map Google user to app user model."""
return {
"external_id": google_user.id,
"email": google_user.email,
"email_verified": google_user.verified_email,
"full_name": google_user.name,
"first_name": google_user.given_name,
"last_name": google_user.family_name,
"avatar_url": google_user.picture,
"locale": google_user.locale,
}
plugin = GoogleOAuthPlugin(
client_id="...",
client_secret="...",
redirect_uri="...",
user_mapper=map_google_user,
)
Custom Scopes
# Request only what you need
plugin = GoogleOAuthPlugin(
client_id="...",
client_secret="...",
redirect_uri="...",
scopes=["openid", "email"], # Just email, no profile
)
# Or request additional scopes
plugin = GoogleOAuthPlugin(
client_id="...",
client_secret="...",
redirect_uri="...",
scopes=[
"openid",
"email",
"profile",
"https://www.googleapis.com/auth/drive.readonly"
],
)
Protected Routes
from flaxon_oauth_google import login_required
@app.get("/profile")
@login_required
async def profile(request):
user = request.session.get("user")
return {
"name": user.get("name"),
"email": user.get("email"),
"picture": user.get("picture"),
}
@app.get("/settings")
@login_required
async def settings(request):
return {"settings": "..."}
OAuth Endpoints
| Route | Method | Description |
|---|---|---|
/auth/google/login |
GET | Redirect to Google consent screen |
/auth/google/callback |
GET | OAuth callback endpoint |
/auth/google/logout |
GET | Clear session (optional) |
/auth/google/user |
GET | Get current user info |
Security Best Practices
✅ Store client secret in environment variables
✅ Use HTTPS in production
✅ Validate redirect URI matches registered URI
✅ Use state parameter for CSRF protection
✅ Verify ID token signature
✅ Keep scopes minimal (least privilege)
✅ Regenerate session ID on login
✅ Use secure cookies (Secure, HttpOnly, SameSite)
Example Application
Complete Setup
from flaxon import Flaxon
from flaxon_oauth_google import GoogleOAuthPlugin
import os
app = Flaxon("my-app")
# Load plugin
plugin = GoogleOAuthPlugin(
client_id=os.environ["GOOGLE_CLIENT_ID"],
client_secret=os.environ["GOOGLE_CLIENT_SECRET"],
redirect_uri=f"{os.environ['APP_URL']}/auth/google/callback",
scopes=["openid", "email", "profile"],
success_redirect="/dashboard",
failure_redirect="/login?error=oauth_failed",
)
def create_session(google_user):
"""Create a session for the user."""
# Your session creation logic
session_id = f"session_{google_user.id}_{int(time.time())}"
return session_id
plugin.session_maker = create_session
app.plugins.load_plugin(plugin)
@app.get("/")
async def home(request):
return """
<html>
<body>
<h1>Welcome to My App</h1>
<a href="/auth/google/login">
<button>Sign in with Google</button>
</a>
</body>
</html>
"""
@app.get("/dashboard")
async def dashboard(request):
user = request.session.get("user")
if not user:
return {"error": "Not authenticated"}, 401
return {
"welcome": f"Hello, {user.get('name')}!",
"email": user.get("email"),
"picture": user.get("picture"),
}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Testing
# Run tests
pytest
# Run with coverage
pytest --cov=flaxon_oauth_google
# Run specific test
pytest tests/test_provider.py -v
Requirements
Python 3.11+
Flaxon 0.1.0+
httpx 0.27.0+
pyjwt 2.8.0+
cryptography 42.0.0+
Project Structure
flaxon-oauth-google/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│ └── flaxon_oauth_google/
│ ├── __init__.py # Public API exports
│ ├── plugin.py # GoogleOAuthPlugin class
│ ├── provider.py # GoogleOAuthProvider
│ ├── client.py # Google API client
│ ├── user.py # User info mapping
│ └── routes.py # OAuth route handlers
└── tests/
├── test_plugin.py
├── test_provider.py
└── test_integration.py
Roadmap
| Version | Features |
|---|---|
| 0.1.0 | Basic Google OAuth flow |
| 0.2.0 | G Suite domain restriction |
| 0.3.0 | Service account support |
| 0.4.0 | Social login buttons (HTML helpers) |
| 0.5.0 | Refresh token rotation |
Contributing
Fork the repository
Create a feature branch
Add tests for new features
Ensure all tests pass
Submit a pull request
License
MIT License - See LICENSE file for details.
Support
📚 Documentation
🐛 Issue Tracker
💬 Discussions
Metadata
Release files for flaxon-oauth-google 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| flaxon_oauth_google-0.1.2.tar.gz | 18.0 kB | Without provenance | Details for flaxon_oauth_google-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| flaxon_oauth_google-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for flaxon_oauth_google-0.1.2-py3-none-any.whl |
Total release size: 31.9 kB
Release files / flaxon_oauth_google-0.1.2.tar.gz
| Download URL | flaxon_oauth_google-0.1.2.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2d3861aa995f8d13f1dea17e57230729600c4ff236cbe0c7896ffadba49e8285
|
|
BLAKE2b-256 checksum How to use checksums |
487212239e250af614aff5181303673707d081111c573f8e4d59fd6ebeee50b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Release files / flaxon_oauth_google-0.1.2-py3-none-any.whl
| Download URL | flaxon_oauth_google-0.1.2-py3-none-any.whl |
|---|---|
| Size | 13.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0ce146649871bbb1fe0f9acb621d7b0f489c8103f2ee0f3b16ce8989c4b484b7
|
|
BLAKE2b-256 checksum How to use checksums |
27d5bd4fc2db9bd1ed856a815579db560e4558e59ac7c5e344b0a4acd390f0df
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.3
|
Security for flaxon-oauth-google 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.