Automated Action 99937b3fd7 Add comprehensive Google OAuth integration for easy login/signup
Features:
- Complete Google OAuth 2.0 integration with ID token and authorization code flows
- Enhanced User model with Google OAuth fields (google_id, is_google_user, email_verified, profile_picture)
- Google OAuth service for token verification and user info extraction
- Multiple authentication endpoints:
  - GET /auth/google/oauth-url (get OAuth URL for frontend)
  - POST /auth/google/login-with-token (direct ID token login)
  - POST /auth/google/login-with-code (authorization code exchange)
- Smart user handling: creates new users or links existing accounts
- Issues own JWT tokens after Google authentication
- Database migration 004 for Google OAuth fields
- Enhanced login logic to handle Google vs password users
- Comprehensive README with Google OAuth setup instructions
- Frontend integration examples for both OAuth flows

Google OAuth automatically:
- Creates user accounts on first login
- Links existing email accounts to Google
- Extracts profile information (name, picture, locale)
- Verifies email addresses
- Issues secure JWT tokens for API access
2025-06-25 05:49:54 +00:00

52 lines
1.9 KiB
Python

from sqlalchemy import Column, Integer, String, DateTime, Boolean
from datetime import datetime
from app.db.base import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
password_hash = Column(String, nullable=True) # Made nullable for Google OAuth users
first_name = Column(String, nullable=True)
last_name = Column(String, nullable=True)
phone = Column(String, nullable=True)
bio = Column(String, nullable=True)
preferred_language = Column(String, default="en")
timezone = Column(String, default="UTC")
# Google OAuth fields
google_id = Column(String, unique=True, nullable=True, index=True)
is_google_user = Column(Boolean, default=False)
email_verified = Column(Boolean, default=False)
profile_picture = Column(String, nullable=True)
created_at = Column(DateTime(timezone=True), nullable=True)
updated_at = Column(DateTime(timezone=True), nullable=True)
def __init__(self, **kwargs):
super().__init__(**kwargs)
if not self.created_at:
self.created_at = datetime.utcnow()
if not self.updated_at:
self.updated_at = datetime.utcnow()
@property
def full_name(self):
"""Get user's full name"""
if self.first_name and self.last_name:
return f"{self.first_name} {self.last_name}"
elif self.first_name:
return self.first_name
elif self.last_name:
return self.last_name
return self.email.split('@')[0] # Fallback to email username
def is_password_user(self):
"""Check if user uses password authentication"""
return self.password_hash is not None and not self.is_google_user
def can_login_with_password(self):
"""Check if user can login with password"""
return self.password_hash is not None