
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
52 lines
1.9 KiB
Python
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 |