This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
shared/models/oauth_code.py
giles 6bb26522a1 Add OAuth grants for per-device session revocation
- OAuthGrant model tracks each client authorization, tied to the
  account session (issuer_session) that issued it
- OAuth authorize creates grant + code together
- Client apps store grant_token in session, verify via account's
  internal /auth/internal/verify-grant endpoint (Redis-cached 60s)
- Account logout revokes only grants from that device's session
- Replaces iframe-based logout with server-side grant revocation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 12:30:08 +00:00

27 lines
1.3 KiB
Python

from __future__ import annotations
from datetime import datetime
from sqlalchemy import String, Integer, DateTime, ForeignKey, func, Index
from sqlalchemy.orm import Mapped, mapped_column, relationship
from shared.db.base import Base
class OAuthCode(Base):
__tablename__ = "oauth_codes"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
code: Mapped[str] = mapped_column(String(128), unique=True, index=True, nullable=False)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
client_id: Mapped[str] = mapped_column(String(64), nullable=False)
redirect_uri: Mapped[str] = mapped_column(String(512), nullable=False)
expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
used_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
grant_token: Mapped[str | None] = mapped_column(String(128), nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
user = relationship("User", backref="oauth_codes")
__table_args__ = (
Index("ix_oauth_code_code", "code", unique=True),
Index("ix_oauth_code_user", "user_id"),
)