Skip to content

Access Token and Refresh Token field length too small #1523

@maxdorninger

Description

@maxdorninger

Describe the bug

The Access Token and Refresh Token field are too small when using Postgres (VARCHAR(1024)).
When using OAuth2 providers like Authentik with a token algorithm like RS256, the access tokens can easily exceed the max length of 1024 chars, thus causing this error:

sqlalchemy.exc.DataError: (psycopg.errors.StringDataRightTruncation) value too long for type character varying(1024)

To Reproduce

Steps to reproduce the behavior:

  1. Setup OAuth authentication with SQLAlchemy. With a table that's defined like this
from fastapi_users.db import (
    SQLAlchemyBaseOAuthAccountTableUUID,
)

class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
    pass
  1. Setup a OAuth provider with access token encryption/signing
  2. Try to login
  3. Fail to login because the access token couldn't be saved.

Expected behavior

The DB column data type being large enough to store the access/refresh token, thus enabling logging in.

Configuration

  • Python version : 3.13
  • FastAPI version : 0.115.12
  • FastAPI Users version : 14.0.1

FastAPI Users configuration

db.py

from collections.abc import AsyncGenerator
from typing import Optional

from fastapi import Depends
from fastapi_users.db import (
    SQLAlchemyBaseUserTableUUID,
    SQLAlchemyUserDatabase,
    SQLAlchemyBaseOAuthAccountTableUUID,
)
from sqlalchemy import String
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import Mapped, relationship, mapped_column

from media_manager.database import Base
from media_manager.database import db_url


class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
    # my current setup already includes a fix for this error, by just overwriting the default type
    access_token: Mapped[str] = mapped_column(String(length=4096), nullable=False)
    refresh_token: Mapped[Optional[str]] = mapped_column(
        String(length=4096), nullable=True
    )
    pass


class User(SQLAlchemyBaseUserTableUUID, Base):
    oauth_accounts: Mapped[list[OAuthAccount]] = relationship(
        "OAuthAccount", lazy="joined"
    )


engine = create_async_engine(db_url, echo=False)
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)


async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
    async with async_session_maker() as session:
        yield session


async def get_user_db(session: AsyncSession = Depends(get_async_session)):
    yield SQLAlchemyUserDatabase(session, User, OAuthAccount)

users.py

import uuid

from fastapi_users import schemas


class UserRead(schemas.BaseUser[uuid.UUID]):
    pass


class UserCreate(schemas.BaseUserCreate):
    pass


class UserUpdate(schemas.BaseUserUpdate):
    pass

Additional context

maxdorninger/MediaManager#35

I'd be happy to help contribute and submit a PR fixing this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions