forked from cardosofelipe/fast-next-template
Initial implementation of OAuth models, endpoints, and migrations
- Added models for `OAuthClient`, `OAuthState`, and `OAuthAccount`. - Created Pydantic schemas to support OAuth flows, client management, and linked accounts. - Implemented skeleton endpoints for OAuth Provider mode: authorization, token, and revocation. - Updated router imports to include new `/oauth` and `/oauth/provider` routes. - Added Alembic migration script to create OAuth-related database tables. - Enhanced `users` table to allow OAuth-only accounts by making `password_hash` nullable.
This commit is contained in:
55
backend/app/models/oauth_account.py
Normal file
55
backend/app/models/oauth_account.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""OAuth account model for linking external OAuth providers to users."""
|
||||
|
||||
from sqlalchemy import Column, DateTime, ForeignKey, Index, String, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import Base, TimestampMixin, UUIDMixin
|
||||
|
||||
|
||||
class OAuthAccount(Base, UUIDMixin, TimestampMixin):
|
||||
"""
|
||||
Links OAuth provider accounts to users.
|
||||
|
||||
Supports multiple OAuth providers per user (e.g., user can have both
|
||||
Google and GitHub connected). Each provider account is uniquely identified
|
||||
by (provider, provider_user_id).
|
||||
"""
|
||||
|
||||
__tablename__ = "oauth_accounts"
|
||||
|
||||
# Link to user
|
||||
user_id = Column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("users.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# OAuth provider identification
|
||||
provider = Column(
|
||||
String(50), nullable=False, index=True
|
||||
) # google, github, microsoft
|
||||
provider_user_id = Column(String(255), nullable=False) # Provider's unique user ID
|
||||
provider_email = Column(
|
||||
String(255), nullable=True, index=True
|
||||
) # Email from provider (for reference)
|
||||
|
||||
# Optional: store provider tokens for API access
|
||||
# These should be encrypted at rest in production
|
||||
access_token_encrypted = Column(String(2048), nullable=True)
|
||||
refresh_token_encrypted = Column(String(2048), nullable=True)
|
||||
token_expires_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# Relationship
|
||||
user = relationship("User", back_populates="oauth_accounts")
|
||||
|
||||
__table_args__ = (
|
||||
# Each provider account can only be linked to one user
|
||||
UniqueConstraint("provider", "provider_user_id", name="uq_oauth_provider_user"),
|
||||
# Index for finding all OAuth accounts for a user + provider
|
||||
Index("ix_oauth_accounts_user_provider", "user_id", "provider"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<OAuthAccount {self.provider}:{self.provider_user_id}>"
|
||||
Reference in New Issue
Block a user