-
-
Notifications
You must be signed in to change notification settings - Fork 79
Tutorial OAuth Login
Enferno includes OAuth authentication out of the box. This tutorial shows how to enable it.
Time: ~15 minutes
Enferno ships with complete OAuth support:
- Google and GitHub login handlers (
enferno/public/views.py) - OAuth model to link providers to users (
enferno/user/models.py) - Automatic account creation for new OAuth users
- Account linking for existing users with matching email
You just need to add your credentials.
- Go to Google Cloud Console
- Create a project (or select existing)
- Navigate to APIs & Services → Credentials
- Click Create Credentials → OAuth client ID
- Select Web application
- Add authorized redirect URI:
- Development:
http://localhost:5000/login/google/authorized - Production:
https://yourdomain.com/login/google/authorized
- Development:
- Copy the Client ID and Client Secret
- Go to GitHub Developer Settings
- Click New OAuth App
- Fill in:
- Application name: Your app name
- Homepage URL:
http://localhost:5000(or production URL) - Authorization callback URL:
http://localhost:5000/login/github/authorized
- Click Register application
- Copy the Client ID and generate a Client Secret
Add to your .env file:
# Google OAuth
GOOGLE_AUTH_ENABLED=true
GOOGLE_OAUTH_CLIENT_ID=your_google_client_id
GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret
# GitHub OAuth
GITHUB_AUTH_ENABLED=true
GITHUB_OAUTH_CLIENT_ID=your_github_client_id
GITHUB_OAUTH_CLIENT_SECRET=your_github_client_secretRestart the server:
uv run flask runVisit http://localhost:5000/login and you should see:
- "Sign in with Google" button
- "Sign in with GitHub" button
Click either to test the flow.
New users: OAuth creates an account automatically using email from the provider. Password is set to a random value with password_set=False so they can set one later.
Existing users: If a user with matching email exists, OAuth links to that account instead of creating a duplicate.
Multiple providers: Users can link multiple OAuth providers to one account.
The OAuth handling is in enferno/public/views.py:
@oauth_authorized.connect
def oauth_logged_in(blueprint, token):
# Get user info from provider
provider_data = get_oauth_user_data(blueprint)
# Check if OAuth entry exists
oauth = OAuth.query.filter_by(
provider=blueprint.name,
provider_user_id=user_id
).one_or_none()
if oauth and oauth.user:
# Existing OAuth user - log them in
login_user(oauth.user)
else:
# Check for existing user with same email
existing_user = User.query.filter_by(email=provider_data["email"]).first()
if existing_user:
# Link OAuth to existing account
oauth.user = existing_user
else:
# Create new user
user = create_oauth_user(provider_data, token, ip_address)
oauth.user = userConfiguration is in enferno/settings.py:
GOOGLE_AUTH_ENABLED = os.environ.get("GOOGLE_AUTH_ENABLED", "False").lower() == "true"
GOOGLE_OAUTH_CLIENT_ID = os.environ.get("GOOGLE_OAUTH_CLIENT_ID")
GOOGLE_OAUTH_CLIENT_SECRET = os.environ.get("GOOGLE_OAUTH_CLIENT_SECRET")
GITHUB_AUTH_ENABLED = os.environ.get("GITHUB_AUTH_ENABLED", "False").lower() == "true"
GITHUB_OAUTH_CLIENT_ID = os.environ.get("GITHUB_OAUTH_CLIENT_ID")
GITHUB_OAUTH_CLIENT_SECRET = os.environ.get("GITHUB_OAUTH_CLIENT_SECRET")Prompt for AI assistant:
Add Twitter/X OAuth login following the same pattern as Google and GitHub. Add settings for TWITTER_AUTH_ENABLED, TWITTER_OAUTH_CLIENT_ID, TWITTER_OAUTH_CLIENT_SECRET. Register the blueprint in app.py and add the handler in public/views.py.
Flask-Dance supports many providers: Twitter, Facebook, Discord, LinkedIn, etc.
| Issue | Solution |
|---|---|
| "Authentication failed" | Check credentials in .env match exactly |
| Redirect URI mismatch | Ensure callback URL in provider console matches exactly |
| Buttons not showing | Check *_AUTH_ENABLED=true is set |
| HTTPS errors locally | Use HTTP for localhost, HTTPS for production |
For production deployment with Ignite:
- Update OAuth callback URLs to use your domain with HTTPS
- Set environment variables on your server
- Ignite handles HTTPS automatically via Caddy