from datetime import datetime from sqlalchemy import Boolean, ForeignKey, Integer, String, Text, func from sqlalchemy.orm import Mapped, mapped_column from app.database import Base class PasskeyCredential(Base): __tablename__ = "passkey_credentials" id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True ) # base64url-encoded credential ID (spec allows up to 1023 bytes → ~1363 chars) credential_id: Mapped[str] = mapped_column(Text, unique=True, nullable=False) # base64url-encoded COSE public key public_key: Mapped[str] = mapped_column(Text, nullable=False) # Authenticator sign count for clone detection sign_count: Mapped[int] = mapped_column(Integer, default=0) # User-assigned label (e.g. "MacBook Pro — Chrome") name: Mapped[str] = mapped_column(String(100), nullable=False) # JSON array of transport hints (e.g. '["usb","hybrid"]') transports: Mapped[str | None] = mapped_column(Text, nullable=True) # Whether the credential is backed up / synced across devices backed_up: Mapped[bool] = mapped_column(Boolean, default=False) created_at: Mapped[datetime] = mapped_column(default=func.now()) last_used_at: Mapped[datetime | None] = mapped_column(nullable=True)