Giter Club home page Giter Club logo

fief's Introduction

Fief

Users and authentication management SaaS

Subscribe

Getting started

Support us

Subscription Tiers on Polar

Contributing

All Contributors

All contributions to improve the project are welcome! In particular, bug and documentation fixes are really appreciated.

For new features and larger improvements, we kindly ask you to open a discussion first about your idea, what motivates it and how you plan to implement it before you start working. It'll avoid frustration on both sides if we decide not to integrate your code in the project.

Thanks goes to these wonderful people (emoji key):

shrike71
shrike71

๐Ÿ› ๐Ÿค”
trisongz
trisongz

๐Ÿ’ก ๐Ÿค”
David Brochart
David Brochart

๐Ÿ“– ๐Ÿ’ป
Paolo Dina
Paolo Dina

๐Ÿ›
duber000
duber000

๐Ÿ’ป
Danilo Polani
Danilo Polani

๐ŸŒ
Moritz
Moritz

๐ŸŒ
plpsanchez
plpsanchez

๐ŸŒ
William Mayor
William Mayor

๐Ÿ’ป
Rui Oliveira
Rui Oliveira

๐ŸŒ ๐Ÿ’ป
Jimmy Angel Pรฉrez Dรญaz
Jimmy Angel Pรฉrez Dรญaz

๐ŸŒ
Michaล‚ Rosiak
Michaล‚ Rosiak

๐ŸŒ
olimcc
olimcc

๐Ÿ›ก๏ธ
Joe Hamman
Joe Hamman

๐Ÿ›ก๏ธ
zfei
zfei

๐ŸŒ ๐Ÿ’ป
Bartosz Magiera
Bartosz Magiera

๐Ÿ“–
oaltun
oaltun

๐Ÿ’ป
Cesar Smaniotto Jรบnior
Cesar Smaniotto Jรบnior

๐ŸŒ
rotil
rotil

๐Ÿ›ก๏ธ
ๆŽ็ง‰็ฅ
ๆŽ็ง‰็ฅ

๐ŸŒ
Lev Dubinets
Lev Dubinets

๐Ÿ’ต
Mathieu Virbel
Mathieu Virbel

๐Ÿ›
corv89
corv89

๐Ÿ›
Yaroslav Polyakov
Yaroslav Polyakov

๐Ÿ’ป
Scott Fredericksen
Scott Fredericksen

๐Ÿ’ป

Development

To get started quickly, we recommend you to use GitHub Codespaces. We have a complete configuration allowing you to start working on Fief right away, including pre-configured PostgreSQL and Redis servers.

Open in GitHub Codespaces

When the Codespace is built, an admin user is automatically created.

Admin user credentials

Email: [email protected]

Password: herminetincture

Run the Fief server in development mode with the following command:

hatch run dev.server.start

The worker can also be started with the following command:

hatch run dev.worker.start

License

Fief is fair-code distributed under Elastic License 2.0 (ELv2).

fief's People

Contributors

allcontributors[bot] avatar davidbrochart avatar duber000 avatar frankie567 avatar oaltun avatar ruipoliveira avatar scottfred avatar williammayor avatar yaroslaff avatar zfei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fief's Issues

auth.css served via http

I've setup self-hosted fief using provided docker-compose.yaml. My reverse proxy is providing SSL with Letsencrypt so I'm accessing fief via https (frankly it's odd that the production deployment documentation does does http by default).

When I try to load the login page the auth.css is retrieved via http rather than https which causes the page to fail.

image

Configuration

image

Internal Server Error (500) when validating access token on service side

Describe the bug

When I access REST API with the access token, provided by Fief, the service responds with 500 Internal Server Error from the token validation functions.

To Reproduce

You need to setup some sample service, using Fief as Identity provider. In my case Fief runs at http://localhost:8001, my service runs at http://localhost:8000.

  1. Create a user
  2. Create a permission
  3. Generate access token
  4. Call service API with the token, provided at step 3. REST API must require the permission from step 2.
  5. See the stack trace below

Expected behavior

Token validation functions shall not raise exceptions in case of a valid token.

Configuration

  • Self-hosted, Fief version: 0.24.3

Additional context

Stack trace:

INFO:     127.0.0.1:60174 - "POST /api/castle/create HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/httpx/_transports/default.py", line 60, in map_httpcore_exceptions
    yield
  File "/usr/local/lib/python3.11/dist-packages/httpx/_transports/default.py", line 353, in handle_async_request
    resp = await self._pool.handle_async_request(req)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/httpcore/_async/connection_pool.py", line 212, in handle_async_request
    raise UnsupportedProtocol(
httpcore.UnsupportedProtocol: Request URL has an unsupported protocol 'localhost://'.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/uvicorn/protocols/http/httptools_impl.py", line 436, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/fastapi/applications.py", line 276, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.11/dist-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/dist-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.11/dist-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/dist-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.11/dist-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.11/dist-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.11/dist-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/dist-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/dist-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/dist-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/fastapi/routing.py", line 227, in app
    solved_result = await solve_dependencies(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/fastapi/dependencies/utils.py", line 592, in solve_dependencies
    solved_result = await solve_dependencies(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/fastapi/dependencies/utils.py", line 621, in solve_dependencies
    solved = await call(**sub_values)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "<makefun-gen-0>", line 2, in _authenticated
  File "/usr/local/lib/python3.11/dist-packages/fief_client/integrations/fastapi.py", line 175, in _authenticated
    info = await result
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/fief_client/client.py", line 892, in validate_access_token
    jwks = await self._get_jwks()
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/fief_client/client.py", line 1013, in _get_jwks
    await self._get_openid_configuration(), "jwks_uri"
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/contextlib.py", line 222, in __aexit__
    await self.gen.athrow(typ, value, traceback)
  File "/usr/local/lib/python3.11/dist-packages/fief_client/client.py", line 995, in _get_httpx_client
    yield client
  File "/usr/local/lib/python3.11/dist-packages/fief_client/client.py", line 1003, in _get_openid_configuration
    response = await client.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/httpx/_client.py", line 1620, in send
    response = await self._send_handling_auth(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/httpx/_client.py", line 1648, in _send_handling_auth
    response = await self._send_handling_redirects(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/httpx/_client.py", line 1685, in _send_handling_redirects
    response = await self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/httpx/_client.py", line 1722, in _send_single_request
    response = await transport.handle_async_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/httpx/_transports/default.py", line 352, in handle_async_request
    with map_httpcore_exceptions():
  File "/usr/lib/python3.11/contextlib.py", line 155, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/usr/local/lib/python3.11/dist-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.UnsupportedProtocol: Request URL has an unsupported protocol 'localhost://'.

I also noticed a non-expected thing in the decoded access token - the 'iss' field contains https://localhost:8001, while I run Fief at http://localhost:8001.

{
 alg: "RS256",
 kid: "G_hwBL1iy-VvSr0uSMvV39xmvNss2ogkZWl7-3gJBEs"
}.
{
 aud: [
  "bla-bla-bla"
 ],
 azp: "bla-bla-bla",
 exp: 1684250951,
 iat: 1684164551,
 iss: "https://localhost:8001",
 permissions: [
  "createCastle"
 ],
 scope: "openid",
 sub: "e4718be2-06b4-4803-a73a-67da56e5c3d0"
}.
[signature]

Since I initialize FiefClient with http://localhost:8001, perhaps, it cannot match Base URLs from the Python code and from the token.

Fief 0.25.1 doesn't start with existing database

Describe the bug

Fief 0.25.1 doesn't start with existing database.

To Reproduce

Steps to reproduce the behavior:
I don't know how to reproduce it for sure, but you can try the following:

  1. Setup Fief 0.24.2: 10 users, 2 permissions, add a custom URI to the Fief's Client, make it public. Database - MySQL server, if it matters
  2. Start Fief 0.25.1 with the same database

Fief raises an exception (UnboundLocalError: cannot access local variable 'user' where it is not associated with a value) on startup

Expected behavior

Successful startup.

Configuration

  • If self-hosted, Fief version: 0.25.1

Additional context

2023-06-02T10:04:16.020490508Z โ”‚ /usr/local/lib/python3.11/site-packages/fief/services/main_workspace.py:151  โ”‚
2023-06-02T10:04:16.020494308Z โ”‚ in create_main_fief_user                                                     โ”‚
2023-06-02T10:04:16.020498108Z โ”‚                                                                              โ”‚
2023-06-02T10:04:16.020501908Z โ”‚   148 โ”‚   โ”‚   โ”‚   โ”‚   user_fields=[],                                        โ”‚
2023-06-02T10:04:16.020505708Z โ”‚   149 โ”‚   โ”‚   โ”‚   )                                                          โ”‚
2023-06-02T10:04:16.020512608Z โ”‚   150 โ”‚   โ”‚                                                                  โ”‚
2023-06-02T10:04:16.020517008Z โ”‚ โฑ 151 โ”‚   โ”‚   workspace_user = WorkspaceUser(workspace_id=workspace.id, user โ”‚
2023-06-02T10:04:16.020520808Z โ”‚   152 โ”‚   โ”‚   await workspace_user_repository.create(workspace_user)         โ”‚
2023-06-02T10:04:16.020524708Z โ”‚   153 โ”‚                                                                      โ”‚
2023-06-02T10:04:16.020528508Z โ”‚   154 โ”‚   return user                                                        โ”‚
2023-06-02T10:04:16.020532308Z โ”‚                                                                              โ”‚
2023-06-02T10:04:16.020559007Z โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
2023-06-02T10:04:16.020563107Z โ”‚ โ”‚                     email = '****.**********@********.com'               โ”‚ โ”‚
2023-06-02T10:04:16.020567107Z โ”‚ โ”‚  main_async_session_maker = async_sessionmaker(class_='AsyncSession',    โ”‚ โ”‚
2023-06-02T10:04:16.020571007Z โ”‚ โ”‚                             bind=<sqlalchemy.ext.asyncio.engine.AsyncEnโ€ฆ โ”‚ โ”‚
2023-06-02T10:04:16.020574907Z โ”‚ โ”‚                             object at 0x7a18199b86c0>, autoflush=True,   โ”‚ โ”‚
2023-06-02T10:04:16.020578707Z โ”‚ โ”‚                             expire_on_commit=False)                      โ”‚ โ”‚
2023-06-02T10:04:16.020582407Z โ”‚ โ”‚                  password = '***********'                                โ”‚ โ”‚
2023-06-02T10:04:16.020586107Z โ”‚ โ”‚                   session = <sqlalchemy.ext.asyncio.session.AsyncSession โ”‚ โ”‚
2023-06-02T10:04:16.020589707Z โ”‚ โ”‚                             object at 0x7a181aeaf210>                    โ”‚ โ”‚
2023-06-02T10:04:16.020593507Z โ”‚ โ”‚         tenant_repository = <fief.repositories.tenant.TenantRepository   โ”‚ โ”‚
2023-06-02T10:04:16.020597107Z โ”‚ โ”‚                             object at 0x7a1819794410>                    โ”‚ โ”‚
2023-06-02T10:04:16.020600807Z โ”‚ โ”‚                 workspace = Workspace(id=1c29d7ce-1121-43a2-a421-d0dbf6โ€ฆ โ”‚ โ”‚
2023-06-02T10:04:16.020604507Z โ”‚ โ”‚                             name=Fief, domain=****.*************.net)    โ”‚ โ”‚
2023-06-02T10:04:16.020608107Z โ”‚ โ”‚ workspace_user_repository = <fief.repositories.workspace_user.Workspaceโ€ฆ โ”‚ โ”‚
2023-06-02T10:04:16.020633707Z โ”‚ โ”‚                             object at 0x7a181977a310>                    โ”‚ โ”‚
2023-06-02T10:04:16.020637707Z โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
2023-06-02T10:04:16.020641907Z โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
2023-06-02T10:04:16.020649407Z UnboundLocalError: cannot access local variable 'user' where it is not 
2023-06-02T10:04:16.020653807Z associated with a value

See the full log:
2023_06_02_fief-0.25.1.log

Getting "Internal server error" when trying to create a user and there is a "Date" field in user fields

Describe the bug

If there's a "Date" field configured in user fields, it won't let the process of user creation complete, yielding a 500 internal server error. Once field is removed, process completes successfully. Please see python exception log

To Reproduce

Steps to reproduce the behavior:

  1. Create a Date field in users field. notice you cannot set a default value for it.
  2. Create a new user via "register" endpoint
  3. request to fief server fails due to 500

Expected behavior

Successfully complete the process and move to login callback page

Additional context

Attaching python server log:

  File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 333, in _sentry_patched_asgi_app
    return await middleware(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 139, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 188, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 183, in _run_app
    return await callback()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 139, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 149, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 146, in _run_app
    return await callback()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 227, in _sentry_exceptionmiddleware_call
    await old_call(self, scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 443, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 271, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 333, in _sentry_patched_asgi_app
    return await middleware(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 139, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 149, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 146, in _run_app
    return await callback()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 118, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/site-packages/asgi_babel/__init__.py", line 76, in __process__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/middlewares/cors.py", line 19, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/gzip.py", line 24, in __call__
    await responder(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/gzip.py", line 44, in __call__
    await self.app(scope, receive, self.send_with_gzip)
  File "/usr/local/lib/python3.11/site-packages/fief/middlewares/csrf.py", line 23, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/fief/middlewares/security_headers.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 227, in _sentry_exceptionmiddleware_call
    await old_call(self, scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 163, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/apps/auth/routers/register.py", line 80, in register
    user = await registration_flow.create_user(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/services/registration_flow.py", line 90, in create_user
    user = await self.user_manager.create_with_fields(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/dependencies/users.py", line 148, in create_with_fields
    default = user_field.get_default()
              ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/models/user_field.py", line 85, in get_default
    return self.configuration["default"]
           ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
KeyError: 'default'

It looks like the registration flow assume any field has default, but "Date" fields are missing defaults.

Crash with TypeError on Fief's startup

Describe the bug

Fief crashes with TypeError on startup

To Reproduce

Steps to reproduce the behavior:

  1. Start Fief with predefined Admin Key in env variable (not sure if this is relevant)
  2. Observe the crash stack

Expected behavior

Normal startup

Configuration

  • If self-hosted, Fief version: 0.24.5

Additional context

Crash stack

2023-05-25 15:04:30.752 | INFO     | fief.worker:<module>:19 - Fief Worker started - {"version": "0.24.5"}
2023-05-25 15:04:30.767 | INFO     | dramatiq.cli:worker_process:412 - Worker process is ready for action. - {}
[2023-05-25 15:04:30,782] [PID 35] [MainThread] [dramatiq.ForkProcess(1)] [INFO] Fork process 'dramatiq.middleware.prometheus:_run_exposition_server' is ready for action.
/usr/local/lib/python3.11/dist-packages/tzlocal/unix.py:192: UserWarning: Can not find any timezone configuration, defaulting to UTC.
  warnings.warn("Can not find any timezone configuration, defaulting to UTC.")
[2023-05-25 15:04:31,274] [PID 34] [MainThread] [dramatiq.ForkProcess(0)] [INFO] Fork process 'fief.scheduler:schedule' is ready for action.
[2023-05-25 15:04:31,275] [PID 34] [MainThread] [apscheduler.scheduler] [INFO] Adding job tentatively -- it will be properly scheduled when the scheduler starts
[2023-05-25 15:04:31,275] [PID 34] [MainThread] [apscheduler.scheduler] [INFO] Adding job tentatively -- it will be properly scheduled when the scheduler starts
[2023-05-25 15:04:31,276] [PID 34] [MainThread] [apscheduler.scheduler] [INFO] Added job "Actor.send" to job store "default"
[2023-05-25 15:04:31,276] [PID 34] [MainThread] [apscheduler.scheduler] [INFO] Added job "Actor.send" to job store "default"
[2023-05-25 15:04:31,277] [PID 34] [MainThread] [apscheduler.scheduler] [INFO] Scheduler started
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 274bc650f9a2, Initial migration
INFO  [alembic.runtime.migration] Running upgrade 274bc650f9a2 -> 696e383aabf2, Add alembic_revision column to Workspace
INFO  [alembic.runtime.migration] Running upgrade 696e383aabf2 -> 4c2bb65882d7, Add database_ssl_mode to Workspace
INFO  [alembic.runtime.migration] Running upgrade 4c2bb65882d7 -> 3b349d4ffa69, Add users_count column to Workspace
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Traceback (most recent call last) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ /usr/local/lib/python3.11/dist-packages/fief/cli.py:482 in run_server        โ”‚
โ”‚                                                                              โ”‚
โ”‚   479 โ”‚   โ”‚   โ”‚   โ”‚   except MainFiefAdminApiKeyAlreadyExists:               โ”‚
โ”‚   480 โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   typer.secho("Main Fief admin API key already exist โ”‚
โ”‚   481 โ”‚                                                                      โ”‚
โ”‚ โฑ 482 โ”‚   asyncio.run(_pre_run_server())                                     โ”‚
โ”‚   483 โ”‚   uvicorn.run("fief.app:app", host=host, port=port)                  โ”‚
โ”‚   484                                                                        โ”‚
โ”‚   485                                                                        โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
โ”‚ โ”‚           _pre_run_server = <function                                    โ”‚ โ”‚
โ”‚ โ”‚                             run_server.<locals>._pre_run_server at       โ”‚ โ”‚
โ”‚ โ”‚                             0x7f6fc540bba0>                              โ”‚ โ”‚
โ”‚ โ”‚ create_main_admin_api_key = True                                         โ”‚ โ”‚
โ”‚ โ”‚          create_main_user = True                                         โ”‚ โ”‚
โ”‚ โ”‚     create_main_workspace = True                                         โ”‚ โ”‚
โ”‚ โ”‚                      host = '0.0.0.0'                                    โ”‚ โ”‚
โ”‚ โ”‚                   migrate = True                                         โ”‚ โ”‚
โ”‚ โ”‚                      port = 8001                                         โ”‚ โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
โ”‚                                                                              โ”‚
โ”‚ /usr/lib/python3.11/asyncio/runners.py:188 in run                            โ”‚
โ”‚                                                                              โ”‚
โ”‚   185 โ”‚   โ”‚   โ”‚   "asyncio.run() cannot be called from a running event loop" โ”‚
โ”‚   186 โ”‚                                                                      โ”‚
โ”‚   187 โ”‚   with Runner(debug=debug) as runner:                                โ”‚
โ”‚ โฑ 188 โ”‚   โ”‚   return runner.run(main)                                        โ”‚
โ”‚   189                                                                        โ”‚
โ”‚   190                                                                        โ”‚
โ”‚   191 def _cancel_all_tasks(loop):                                           โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
โ”‚ โ”‚  debug = XXX                                                            โ”‚ โ”‚
โ”‚ โ”‚   main = <coroutine object run_server.<locals>._pre_run_server at        โ”‚ โ”‚
โ”‚ โ”‚          0x7f6fc5f662a0>                                                 โ”‚ โ”‚
โ”‚ โ”‚ runner = <asyncio.runners.Runner object at 0x7f6fc5417f90>               โ”‚ โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
โ”‚                                                                              โ”‚
โ”‚ /usr/lib/python3.11/asyncio/runners.py:120 in run                            โ”‚
โ”‚                                                                              โ”‚
โ”‚   117 โ”‚   โ”‚   try:                                                           โ”‚
โ”‚   118 โ”‚   โ”‚   โ”‚   if self._set_event_loop:                                   โ”‚
โ”‚   119 โ”‚   โ”‚   โ”‚   โ”‚   events.set_event_loop(self._loop)                      โ”‚
โ”‚ โฑ 120 โ”‚   โ”‚   โ”‚   return self._loop.run_until_complete(task)                 โ”‚
โ”‚   121 โ”‚   โ”‚   except exceptions.CancelledError:                              โ”‚
โ”‚   122 โ”‚   โ”‚   โ”‚   if self._interrupt_count > 0:                              โ”‚
โ”‚   123 โ”‚   โ”‚   โ”‚   โ”‚   uncancel = getattr(task, "uncancel", None)             โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
โ”‚ โ”‚        context = <_contextvars.Context object at 0x7f6fc5417700>         โ”‚ โ”‚
โ”‚ โ”‚           coro = <coroutine object run_server.<locals>._pre_run_server   โ”‚ โ”‚
โ”‚ โ”‚                  at 0x7f6fc5f662a0>                                      โ”‚ โ”‚
โ”‚ โ”‚           self = <asyncio.runners.Runner object at 0x7f6fc5417f90>       โ”‚ โ”‚
โ”‚ โ”‚ sigint_handler = None                                                    โ”‚ โ”‚
โ”‚ โ”‚           task = <Task finished name='Task-1'                            โ”‚ โ”‚
โ”‚ โ”‚                  coro=<run_server.<locals>._pre_run_server() done,       โ”‚ โ”‚
โ”‚ โ”‚                  defined at                                              โ”‚ โ”‚
โ”‚ โ”‚                  /usr/local/lib/python3.11/dist-packages/fief/cli.py:40โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                  exception=TypeError("'<=' not supported between         โ”‚ โ”‚
โ”‚ โ”‚                  instances of 'OptionInfo' and 'int'")>                  โ”‚ โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
โ”‚                                                                              โ”‚
โ”‚ /usr/lib/python3.11/asyncio/base_events.py:650 in run_until_complete         โ”‚
โ”‚                                                                              โ”‚
โ”‚    647 โ”‚   โ”‚   if not future.done():                                         โ”‚
โ”‚    648 โ”‚   โ”‚   โ”‚   raise RuntimeError('Event loop stopped before Future comp โ”‚
โ”‚    649 โ”‚   โ”‚                                                                 โ”‚
โ”‚ โฑ  650 โ”‚   โ”‚   return future.result()                                        โ”‚
โ”‚    651 โ”‚                                                                     โ”‚
โ”‚    652 โ”‚   def stop(self):                                                   โ”‚
โ”‚    653 โ”‚   โ”‚   """Stop running the event loop.                               โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
โ”‚ โ”‚   future = <Task finished name='Task-1'                                  โ”‚ โ”‚
โ”‚ โ”‚            coro=<run_server.<locals>._pre_run_server() done, defined at  โ”‚ โ”‚
โ”‚ โ”‚            /usr/local/lib/python3.11/dist-packages/fief/cli.py:408>      โ”‚ โ”‚
โ”‚ โ”‚            exception=TypeError("'<=' not supported between instances of  โ”‚ โ”‚
โ”‚ โ”‚            'OptionInfo' and 'int'")>                                     โ”‚ โ”‚
โ”‚ โ”‚ new_task = False                                                         โ”‚ โ”‚
โ”‚ โ”‚     self = <_UnixSelectorEventLoop running=False closed=True             โ”‚ โ”‚
โ”‚ โ”‚            debug=False>                                                  โ”‚ โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
โ”‚                                                                              โ”‚
โ”‚ /usr/local/lib/python3.11/dist-packages/fief/cli.py:411 in _pre_run_server   โ”‚
โ”‚                                                                              โ”‚
โ”‚   408 โ”‚   async def _pre_run_server():                                       โ”‚
โ”‚   409 โ”‚   โ”‚   if migrate:                                                    โ”‚
โ”‚   410 โ”‚   โ”‚   โ”‚   migrate_main()                                             โ”‚
โ”‚ โฑ 411 โ”‚   โ”‚   โ”‚   migrate_workspaces()                                       โ”‚
โ”‚   412 โ”‚   โ”‚                                                                  โ”‚
โ”‚   413 โ”‚   โ”‚   if create_main_workspace:                                      โ”‚
โ”‚   414 โ”‚   โ”‚   โ”‚   from fief.services.main_workspace import (                 โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ                                         โ”‚
โ”‚ โ”‚ create_main_admin_api_key = True โ”‚                                         โ”‚
โ”‚ โ”‚          create_main_user = True โ”‚                                         โ”‚
โ”‚ โ”‚     create_main_workspace = True โ”‚                                         โ”‚
โ”‚ โ”‚                   migrate = True โ”‚                                         โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ                                         โ”‚
โ”‚                                                                              โ”‚
โ”‚ /usr/local/lib/python3.11/dist-packages/fief/cli.py:128 in                   โ”‚
โ”‚ migrate_workspaces                                                           โ”‚
โ”‚                                                                              โ”‚
โ”‚   125 โ”‚   โ”‚   )                                                              โ”‚
โ”‚   126 โ”‚   โ”‚                                                                  โ”‚
โ”‚   127 โ”‚   โ”‚   migrations: dict[concurrent.futures.Future, Workspace] = {}    โ”‚
โ”‚ โฑ 128 โ”‚   โ”‚   with concurrent.futures.ProcessPoolExecutor(                   โ”‚
โ”‚   129 โ”‚   โ”‚   โ”‚   max_workers=max_workers                                    โ”‚
โ”‚   130 โ”‚   โ”‚   ) as executor:                                                 โ”‚
โ”‚   131 โ”‚   โ”‚   โ”‚   for workspace in session.execute(local_workspaces_query).s โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
โ”‚ โ”‚     byod_workspaces_query = <sqlalchemy.sql.selectable.Select object at  โ”‚ โ”‚
โ”‚ โ”‚                             0x7f6fc4c92210>                              โ”‚ โ”‚
โ”‚ โ”‚              connect_args = {}                                           โ”‚ โ”‚
โ”‚ โ”‚                    engine = Engine(sqlite:////opt/src/fief.db)           โ”‚ โ”‚
โ”‚ โ”‚           latest_revision = 'deb3261a9742'                               โ”‚ โ”‚
โ”‚ โ”‚    local_workspaces_query = <sqlalchemy.sql.selectable.Select object at  โ”‚ โ”‚
โ”‚ โ”‚                             0x7f6fc4c862d0>                              โ”‚ โ”‚
โ”‚ โ”‚               max_workers = <typer.models.OptionInfo object at           โ”‚ โ”‚
โ”‚ โ”‚                             0x7f6fc62a9910>                              โ”‚ โ”‚
โ”‚ โ”‚                migrations = {}                                           โ”‚ โ”‚
โ”‚ โ”‚ outdated_workspaces_query = <sqlalchemy.sql.selectable.Select object at  โ”‚ โ”‚
โ”‚ โ”‚                             0x7f6fc514fc90>                              โ”‚ โ”‚
โ”‚ โ”‚                   Session = sessionmaker(class_='Session',               โ”‚ โ”‚
โ”‚ โ”‚                             bind=Engine(sqlite:////opt/src/fief.db),     โ”‚ โ”‚
โ”‚ โ”‚                             autoflush=True, expire_on_commit=True)       โ”‚ โ”‚
โ”‚ โ”‚                   session = <sqlalchemy.orm.session.Session object at    โ”‚ โ”‚
โ”‚ โ”‚                             0x7f6fc4c77550>                              โ”‚ โ”‚
โ”‚ โ”‚                  settings = Settings(                                    โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   environment=<Environment.PRODUCTION:     โ”‚ โ”‚
โ”‚ โ”‚                             'production'>,                               โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   log_level='INFO',                        โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   sentry_dsn_server=None,                  โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   sentry_dsn_worker=None,                  โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   telemetry_enabled=False,                 โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   root_domain='localhost:8001',            โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             allow_origin_regex='http://.*localhost:[0-9โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   port=8001,                               โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   secret=XXX('**********'),          โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             encryption_key=b'f0iywuJAcl0k0m1CPoQTvuN8ogโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   generated_jwk_size=4096,                 โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_type=<DatabaseType.SQLITE:      โ”‚ โ”‚
โ”‚ โ”‚                             'SQLITE'>,                                   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_url=None,                       โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_host=None,                      โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_port=None,                      โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_username=None,                  โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_password=None,                  โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_name='fief.db',                 โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_ssl_mode=None,                  โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_location=PosixPath('/opt/src'), โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_pool_recycle_seconds=600,       โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   database_pool_pre_ping=False,            โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   redis_url='redis://localhost:6379',      โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             email_provider=<AvailableEmailProvider.NULL: โ”‚ โ”‚
โ”‚ โ”‚                             'NULL'>,                                     โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   email_provider_params={},                โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   default_from_email='[email protected]',   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   default_from_name='Fief',                โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   workspace_table_prefix='fief_',          โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   csrf_check_enabled=True,                 โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   csrf_cookie_name='fief_csrftoken',       โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   csrf_cookie_secure=True,                 โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             session_data_cookie_name='fief_session_dataโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   session_data_cookie_domain='',           โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   session_data_cookie_secure=True,         โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             session_data_cookie_lifetime_seconds=None,   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   user_locale_cookie_name='fief_locale',   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   user_locale_cookie_domain='',            โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   user_locale_cookie_secure=True,          โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   user_locale_lifetime_seconds=2592000,    โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             login_hint_cookie_name='fief_login_hint',    โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   login_hint_cookie_domain='',             โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   login_hint_cookie_secure=True,           โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             login_hint_cookie_lifetime_seconds=2592000,  โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             login_session_cookie_name='fief_login_sessiโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   login_session_cookie_domain='',          โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   login_session_cookie_secure=True,        โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   login_session_lifetime_seconds=600,      โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             registration_session_cookie_name='fief_regiโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   registration_session_cookie_domain='',   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   registration_session_cookie_secure=True, โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             registration_session_lifetime_seconds=600,   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   oauth_session_lifetime_seconds=600,      โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   session_cookie_name='fief_session',      โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   session_cookie_domain='',                โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   session_cookie_secure=True,              โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   session_lifetime_seconds=2592000,        โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             default_authorization_code_lifetime_secondsโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             default_access_id_token_lifetime_seconds=86โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             default_refresh_token_lifetime_seconds=2592โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   fief_domain='localhost:8001',            โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_client_id='35โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_client_secret='aaโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   fief_encryption_key=None,                โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_main_user_email='[email protected]โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_main_user_password=SecretStr('********โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_main_admin_api_key=SecretStr('********โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_admin_session_cookie_name='fief_admin_โ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   fief_admin_session_cookie_domain='',     โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   fief_admin_session_cookie_secure=True,   โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚                                            โ”‚ โ”‚
โ”‚ โ”‚                             fief_documentation_url='https://docs.fief.dโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             โ”‚   webhooks_max_attempts=5                  โ”‚ โ”‚
โ”‚ โ”‚                             )                                            โ”‚ โ”‚
โ”‚ โ”‚                       url = sqlite:////opt/src/fief.db                   โ”‚ โ”‚
โ”‚ โ”‚                 Workspace = <class 'fief.models.workspace.Workspace'>    โ”‚ โ”‚
โ”‚ โ”‚              workspace_db = <fief.services.workspace_db.WorkspaceDatabaโ€ฆ โ”‚ โ”‚
โ”‚ โ”‚                             object at 0x7f6fc4c75410>                    โ”‚ โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
โ”‚                                                                              โ”‚
โ”‚ /usr/lib/python3.11/concurrent/futures/process.py:639 in __init__            โ”‚
โ”‚                                                                              โ”‚
โ”‚   636 โ”‚   โ”‚   โ”‚   โ”‚   self._max_workers = min(_MAX_WINDOWS_WORKERS,          โ”‚
โ”‚   637 โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   self._max_workers)             โ”‚
โ”‚   638 โ”‚   โ”‚   else:                                                          โ”‚
โ”‚ โฑ 639 โ”‚   โ”‚   โ”‚   if max_workers <= 0:                                       โ”‚
โ”‚   640 โ”‚   โ”‚   โ”‚   โ”‚   raise ValueError("max_workers must be greater than 0") โ”‚
โ”‚   641 โ”‚   โ”‚   โ”‚   elif (sys.platform == 'win32' and                          โ”‚
โ”‚   642 โ”‚   โ”‚   โ”‚   โ”‚   max_workers > _MAX_WINDOWS_WORKERS):                   โ”‚
โ”‚                                                                              โ”‚
โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
โ”‚ โ”‚            initargs = ()                                                 โ”‚ โ”‚
โ”‚ โ”‚         initializer = None                                               โ”‚ โ”‚
โ”‚ โ”‚ max_tasks_per_child = None                                               โ”‚ โ”‚
โ”‚ โ”‚         max_workers = <typer.models.OptionInfo object at 0x7f6fc62a9910> โ”‚ โ”‚
โ”‚ โ”‚          mp_context = None                                               โ”‚ โ”‚
โ”‚ โ”‚                self = <concurrent.futures.process.ProcessPoolExecutor    โ”‚ โ”‚
โ”‚ โ”‚                       object at 0x7f6fc4c93e90>                          โ”‚ โ”‚
โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
TypeError: '<=' not supported between instances of 'OptionInfo' and 'int'

As a workspace admin, I want OAuth Provider errors to be handled gracefully, so that I know what's going wrong

Example error reported in Sentry:

{'error': {'code': 403, 'message': 'People API has not been used in project 30480391107 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/people.googleapis.com/overview?project=30480391107 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.', 'status': 'PERMISSION_DENIED', 'details': [{'@type': 'type.googleapis.com/google.rpc.Help', 'links': [{'description': 'Google developers console API activation', 'url': 'https://console.developers.google.com/apis/api/people.googleapis.com/overview?project=30480391107'}]}, {'@type': 'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'SERVICE_DISABLED', 'domain': 'googleapis.com', 'metadata': {'consumer': 'projects/30480391107', 'service': 'people.googleapis.com'}}]}}

An error should be shown when trying to call /authorize and /api/token with a client from another tenant

Describe the bug

Currently, if you make an OAuth2 process with a CLIENT_ID tied to a sub-tenant, you can go through the whole process by calling the root /authorize and /api/token.

It's only at the end of the /api/token call that you'll get a grant_error (because we try to look for a user in the wrong tenant).

To Reproduce

On a workspace with several tenants:

  1. Use a client from a sub-tenant
  2. Make the OAuth2 process using the routes from the main tenant

Expected behavior

An error shall be shown immediately on /authorize to prevent the user to go through the OAuth2 process.

Configuration

  • Cloud or self-hosted: Both

Internal server error when signing in?

Describe the bug

I get an internal server error when I try to sign in after opening an auth url that has been set up to show the register screen first.

To Reproduce

I created a auth url using the flask integration and the following code:

redirect_uri = url_for("signup_callback", _external=True)
auth_url = fief.auth_url(
    redirect_uri,
    scope=["openid"],
    extras_params={"screen": "register"},
)
return redirect(auth_url)

When opening that page I then navigated to the sign in page and tried to sign in. I got an internal server error page.

I can sign in using this account if I create the auth_url without the extras_params bit so I think it's something to do with that?

Expected behavior

I expected to be signed in and redirected to my app.

Configuration

  • Cloud

OpenAPI: default values for Client's lifetimes are misleading

Following #211 and #194, we found out that, by default, OpenAPI sets default values for authorization_code_lifetime_seconds, access_id_token_lifetime_seconds and refresh_token_lifetime_seconds to 0.

This is misleading because, as we've seen, developers can copy/paste the whole example payload and inadvertently set the token lifetime to zero.

We should tweak the Pydantic schema so OpenAPI shows more sensible values.

BTW, maybe we should reconsider the minimum validation for those values, which is currently 0.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

Permission from roles are not applied to users with role

Describe the bug

user with role with some permission does not pass authentication which request that permission

A clear and concise description of what the bug is.
we can create roles and add permissions to it
then we can add role to user

so we expect that user has that permissions

To Reproduce

Steps to reproduce the behavior:

  1. have role with permission , and assign that role to user
    image
    image

  2. Click on user permissions you will see no permissions
    image

  3. try authentication with permission -> result in forbidden

BUT

  1. add permission to user explicitly
    image
  2. auth now pass

Expected behavior

add permission from roles to users with its roles

Configuration

  • Cloud or self-hosted: Cloud

Additional context

Add any other context about the problem here.
no

As a system administrator, I want the startup command to automatically create the main workspace and first superuser, so that I can start the system without manual operations

Plan of the changes:

  • Add fief_admin_email setting. It's optional, with a default to None.
  • Add fief_admin_password setting. It's optional, with a default to None.
  • In the run_server command:
    • Check if the main workspace exists. If not, create it.
    • If fief_admin_email is not None, check if a corresponding user exists.
      • If not, create it. If fief_admin_password is None, generate a random password.

docker exec

Describe the bug

pydantic.error_wrappers.ValidationError: 1 validation error for Settings
fief_client_id
field required (type=value_error.missing)

To Reproduce

Steps to reproduce the behavior:

  1. docker run --name fief-server -p 8000:8000 -d -e "SECRET=qgPj0aESg2JJMXzsykxI2zLMycd0yiehJn8PpXcL78NfwdCx31VRStu_pwlzEl4B0_CYmQwbmlwFS4p4xKoAtw" -e "FIEF_CLIENT_SECRET=XYQdiF_mPEfyc6L3noelZoHptVZ-aCu1lNhk_N77OYs" -e "ENCRYPTION_KEY=YmNSWgnMNepamUSXkxrN2C9YNs9BgCy1UHJzsKRXcWc=" ghcr.io/fief-dev/fief:latest
    8369d8594b45209ef240f967215efb025891521236ebc5f9bb0bc21681f6c692
  2. docker exec fief-server fief workspaces create-main

Configuration

  • If self-hosted, Fief version:

image

Granted by default roles are processed in the worker, so it's not working as expected on first login

Roles have a granted by default feature allowing workspace admin to grant a role automatically to new users as they register. It's useful so we're sure a user have a basic set of permissions right away.

However, the current implementation does this work asynchronously in the background worker (inside OnAfterRegisterTask). This is not very convenient because, when the new user is redirected to the application, the access token generated won't have the default permissions, as the worker probably didn't process the task yet.

We need to improve the implementation so those default roles/permissions are added right away after registration. It might add a bit of overhead in the request, but it would be much more consistent and sensible for the end-developer.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

httpx.ConnectError: All connection attempts failed - Wrong http scheme being selected?

Got round to setting up an https (self-signed) test environment for local testing before putting it out onto our test AWS envs. Installation seemed to go well up to and until running the https://<mysite>/admin/ bit to complete the walkthough of the fief workspace, which returned an 'Internal Server Error':

redir_url

for this docker-compose.yml setup:

version: "3.9"

services:
  fief:
    container_name: fief
    hostname: fief
    image: ghcr.io/fief-dev/fief:latest
    ports:
      - "8001:8001"
    environment:
      - PORT=8001  # Run Uvicorn on 8001 to match the external port
      - LOG_LEVEL=DEBUG  # Run Uvicorn on 8001 to match the external port
      - DATABASE_TYPE=POSTGRESQL
      - DATABASE_URL=postgresql://postgres:postgres@postgres-eval_db_1:5432/fief
      - SECRET=*************
      - FIEF_CLIENT_ID=***********
      - FIEF_CLIENT_SECRET=**********
      - ENCRYPTION_KEY=********
      - ROOT_DOMAIN=fief.ingress.local
      - FIEF_DOMAIN=fief.ingress.local
      - FIEF_BASE_URL=https://fief.ingress.local
      - CSRF_COOKIE_SECURE=False
      - LOGIN_SESSION_COOKIE_SECURE=False
      - SESSION_COOKIE_SECURE=False
      - FIEF_ADMIN_SESSION_COOKIE_SECURE=False
    volumes:
      - fief-server-data:/data
    restart: unless-stopped
    extra_hosts:
        - "ingress.local:127.0.0.1"  # Map ingress.local hostname to localhost inside container
        - "fief.ingress.local:127.0.0.1"  # Map ingress.local hostname to localhost inside container
    networks:
      - eval

volumes:
  fief-server-data:
    external: true

networks:
  eval:
    external: true

I ended up putting uvicorn into debug mode and i put some print statements into

apps/admin/routers/auth.py at about line 22 to spit out the URI:

Here's the relevant part of the stack trace:

[2022-05-12 06:19:45,672] [PID 10] [MainThread] [dramatiq.MainProcess] [INFO] Dramatiq '1.12.3' is booting up.
[2022-05-12 06:19:45,670] [PID 15] [MainThread] [dramatiq.WorkerProcess(0)] [INFO] Worker process is ready for action.
[2022-05-12 06:19:45,679] [PID 22] [MainThread] [dramatiq.ForkProcess(0)] [INFO] Fork process 'dramatiq.middleware.prometheus:_run_exposition_server' is ready for action.
INFO:     Started server process [17]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     172.18.0.7:45702 - "GET /auth/userinfo HTTP/1.1" 401 Unauthorized
INFO:     172.18.0.7:45704 - "GET /workspaces/ HTTP/1.1" 401 Unauthorized
redir_uri: http://fief.ingress.local/admin/api/auth/callback
INFO:     172.18.0.7:45706 - "GET /auth/login?redirect_uri=https%3A%2F%2Ffief.ingress.local%2Fadmin%2F HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 372, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/debug.py", line 96, in __call__
    raise exc from None
  File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/debug.py", line 93, in __call__
    await self.app(scope, receive, inner_send)
  File "/usr/local/lib/python3.10/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 115, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
  File "/usr/local/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 162, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 159, in _run_app
    return await callback()
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 408, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 61, in app
    response = await func(request)
  File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 227, in app
    raw_response = await run_endpoint_function(
  File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 160, in run_endpoint_function
    return await dependant.call(**values)
  File "/usr/local/lib/python3.10/site-packages/fief/apps/admin/routers/auth.py", line 23, in login
    url = await fief.auth_url(
  File "/usr/local/lib/python3.10/site-packages/fief_client/client.py", line 374, in auth_url
    openid_configuration = await self._get_openid_configuration()
  File "/usr/local/lib/python3.10/site-packages/fief_client/client.py", line 463, in _get_openid_configuration
    response = await client.send(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1593, in send
    response = await self._send_handling_auth(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1621, in _send_handling_auth
    response = await self._send_handling_redirects(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1658, in _send_handling_redirects
    response = await self._send_single_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1695, in _send_single_request
    response = await transport.handle_async_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 352, in handle_async_request
    with map_httpcore_exceptions():
  File "/usr/local/lib/python3.10/contextlib.py", line 153, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.ConnectError: All connection attempts failed

The debug line above is labeled 'redir_uri:'. What's bothering me is that it is an 'http' scheme instead of 'https'. Might this be the issue? FWIW, i also took out any 'http' only entries in the DB using PGAdmin ... but it does not make any difference.

Ingress is controlled by NGINX proxy manager, with a self-signed cert, https-only access and HTTP/2 support set up:

fief_nginx

And FWIW, there's full access from the proxy to each container, and I can also 'curl' in between each container

Email Templates/Themes sub-menu is not accessible when menu is in compact mode

Describe the bug:

The Email-Templates/Theme under customization menu has a sub-menu which is not visible when the menu is in compact mode. Hence, we can't access the page:

Screenshot 2023-02-06 171124

Note

The same issue can be found here #54 which is for Permission/roles not shown when seen under compact mode.

To Reproduce

Steps to reproduce the behavior:

1.Go to the admin dashboard
2.If needed, reduce the size of the window to have the compact menu
3.Click on the lock icon
4.Nothing happens

Expected behavior

Probably the easiest solution is to get rid of the compact menu and only display the burger button to switch the mobile menu.

"Internal Server Error" when login to Fief in browser after HTTP/PATCH via REST API

Describe the bug

When I try to login to Fief in browser after modifying the Fief's client via Admin REST API, I see "Internal Server Error" in the browser.

To Reproduce

Steps to reproduce the behavior:

  1. Start Fief with the initial Admin Key
  2. Go to /admin/api/docs
  3. Authorize with the Admin Key
  4. Execute GET /clients/ to see the parameters of the existing client, it's "Fief's client"
  5. Go to PATCH /clients/{id}
  6. Enter id from the step 4 to the id's field
  7. Enter redirect URIs from the step 4 to the PATCH payload
  8. Enter client name from the step 4
  9. Execute the request, you should get 200 OK and a valid response body
  10. Now open browser and open Fief's admin page, /admin
  11. Fief will ask to login
  12. After entering the admin's credentials, browser shows "Internal Server Error"

Expected behavior

A Fief dashboard shall be shown after a successful login.

Configuration

  • If self-hosted, Fief version: 0.24.3 - 0.25.1

Additional context

Fief doesn't print any call stack to console in this case.

UserFieldConfiguration doesn't comply with the schema when created from dashboard

When we create a UserField from admin dashboard, the configuration field may not follow the schema of UserFieldConfiguration.

Typically, when creating a date field, the form doesn't show the default field. Therefore, it's not included in the serialization when saved to DB. This has caused bugs like #165.

When creating from the API, it doesn't happen because the Pydantic schema make sure to add the field with None value.

We should improve this so the configuration field conforms to the schema even when created/updated from the dashboard.

Login session tenant is incorrectly checked in /oauth/callback

Discussed in https://github.com/orgs/fief-dev/discussions/254

Originally posted by tito August 18, 2023
Hi,

I have a self-hosted version of Fief (0.26.0), with the default Fief workspace and multiple Tenant.
I configured Github OAuth as described, and activated for a specific tenant.

From my Next JS app, i see the following process:

  1. https://myapp.com/login (provided by fief-js) -> returns HTTP 307
  2. https://fief.myapp.com/mytenant/authorize?response_type=code&... -> returns HTTP 302
  3. https://fief.myapp.com/mytenant/login -> returns HTTP 200
  4. I click on the github button
  5. https://fief.myapp.com/oauth/authorize?tenant=xxxxxxx&provider=xxxxxxx -> returns HTTP 302
  6. https://github.com/login/oauth/authorize?response_type=code&client_id=xxxx&redirect_uri=https%3A%2F%2Ffief.myapp.com%2Foauth%2Fcallback&state=xxxx&scope=offline_access+openid+user+user%3Aemail -> returns HTTP 302
  7. https://fief.myapp.com/oauth/callback?code=xxxx&state=xxxx -> returns HTTP 400

With the error "Invalid login session"

What did i do wrong ?

Wrong user returned?

I'm not sure if this is an issue or if i'm interpreting this wrongly.... after adding an additional user '[email protected]' to the fief tenant's user directory, I've been able to check auth / not auth on the swagger /docs site with success after adding my custom redirect location for /docs "http://ingress.local:8001/docs/oauth2-redirect" to the redirect_urls column value of fief_clients:

Screenshot 2022-04-29 115920

However as i was running "/api/userinfo" after authentication I was seeing this in the response:

Screenshot 2022-04-29 120046

[email protected] is the fief setup admin. Should that not be [email protected] ?

Thanks

500 Internal Server Error

I encountered the following error when accessing the "/admin/auth/login" endpoint:

TraceInfo:

INFO:     10.244.0.103:0 - "GET /auth/login HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 436, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 276, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 333, in _sentry_patched_asgi_app
    return await middleware(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 139, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 188, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 183, in _run_app
    return await callback()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/middlewares/x_forwarded_host.py", line 26, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 139, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 149, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 146, in _run_app
    return await callback()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 227, in _sentry_exceptionmiddleware_call
    await old_call(self, scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 443, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 276, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 333, in _sentry_patched_asgi_app
    return await middleware(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 139, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 149, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/asgi.py", line 146, in _run_app
    return await callback()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/sessions.py", line 86, in __call__
    await self.app(scope, receive, send_wrapper)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/gzip.py", line 24, in __call__
    await responder(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/gzip.py", line 44, in __call__
    await self.app(scope, receive, self.send_with_gzip)
  File "/usr/local/lib/python3.11/site-packages/fief/middlewares/csrf.py", line 23, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/fief/middlewares/security_headers.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 227, in _sentry_exceptionmiddleware_call
    await old_call(self, scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/starlette.py", line 130, in _create_span_call
    return await old_call(app, scope, new_receive, new_send, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 163, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief/apps/dashboard/routers/auth.py", line 24, in login
    url = await fief.auth_url(
          ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief_client/client.py", line 764, in auth_url
    openid_configuration = await self._get_openid_configuration()
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fief_client/client.py", line 1003, in _get_openid_configuration
    response = await client.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/httpx/_client.py", line 1620, in send
    response = await self._send_handling_auth(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/httpx/_client.py", line 1648, in _send_handling_auth
    response = await self._send_handling_redirects(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/httpx/_client.py", line 1685, in _send_handling_redirects
    response = await self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/httpx/_client.py", line 1722, in _send_single_request
    response = await transport.handle_async_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/httpx/_transports/default.py", line 352, in handle_async_request
    with map_httpcore_exceptions():
  File "/usr/local/lib/python3.11/contextlib.py", line 155, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/usr/local/lib/python3.11/site-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.ConnectError: All connection attempts failed

To Reproduce

  1. Install Fief by docker-compose standalone
  2. vist https://mydomain/admin/auth/login

Permissions/Roles menu is not accessible when menu is in compact mode

Describe the bug

The permissions/roles menu has a sub-menu which is not visible when the menu is in compact mode. Hence, we can't access the page:

Capture dโ€™eฬcran 2022-07-25 aฬ€ 09 19 13

To Reproduce

Steps to reproduce the behavior:

  1. Go to the admin dashboard
  2. If needed, reduce the size of the window to have the compact menu
  3. Click on the lock icon
  4. Nothing happens

Expected behavior

Probably the easiest solution is to get rid of the compact menu and only display the burger button to switch the mobile menu.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

User verification email failing

Describe the bug

Fief got auto updated in docker this morning. All of the sudden, current user must verify their email, and we didn't have any email provider setup as it was not necessary.

Then, after setting an smtp we got:

stacks-fief-1  | 2023-08-18 14:54:19.716 | ERROR    | dramatiq.worker:process_message:513 - Failed to process message on_email_verification_requested('0d4e8575-eb5b-48f4-95c1-2a50e9dcf08e', '74272c99-3631-4cba-a61f-f11ba3c88275', '9V5SB4') with unhandled exception. - {}
stacks-fief-1  | Traceback (most recent call last):
stacks-fief-1  | 
stacks-fief-1  |   File "/usr/local/lib/python3.11/threading.py", line 995, in _bootstrap
stacks-fief-1  |     self._bootstrap_inner()
stacks-fief-1  |     โ”‚    โ”” <function Thread._bootstrap_inner at 0x7fa9f101a8e0>
stacks-fief-1  |     โ”” <_WorkerThread(Thread-5, started daemon 140367517185728)>
stacks-fief-1  |   File "/usr/local/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
stacks-fief-1  |     self.run()
stacks-fief-1  |     โ”‚    โ”” <function _WorkerThread.run at 0x7fa9e9864040>
stacks-fief-1  |     โ”” <_WorkerThread(Thread-5, started daemon 140367517185728)>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/threading.py", line 70, in run
stacks-fief-1  |     return old_run_func(self, *a, **kw)
stacks-fief-1  |            โ”‚            โ”‚      โ”‚    โ”” {}
stacks-fief-1  |            โ”‚            โ”‚      โ”” ()
stacks-fief-1  |            โ”‚            โ”” <_WorkerThread(Thread-5, started daemon 140367517185728)>
stacks-fief-1  |            โ”” <function _WorkerThread.run at 0x7fa9eec94040>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/dramatiq/worker.py", line 460, in run
stacks-fief-1  |     self.process_message(message)
stacks-fief-1  |     โ”‚    โ”‚               โ”” <dramatiq.broker.MessageProxy object at 0x7fa9da001bd0>
stacks-fief-1  |     โ”‚    โ”” <function _WorkerThread.process_message at 0x7fa9eec940e0>
stacks-fief-1  |     โ”” <_WorkerThread(Thread-5, started daemon 140367517185728)>
stacks-fief-1  | > File "/usr/local/lib/python3.11/site-packages/dramatiq/worker.py", line 485, in process_message
stacks-fief-1  |     res = actor(*message.args, **message.kwargs)
stacks-fief-1  |           โ”‚      โ”‚               โ”” <dramatiq.broker.MessageProxy object at 0x7fa9da001bd0>
stacks-fief-1  |           โ”‚      โ”” <dramatiq.broker.MessageProxy object at 0x7fa9da001bd0>
stacks-fief-1  |           โ”” Actor(<fief.tasks.email_verification.OnEmailVerificationRequestedTask object at 0x7fa9ea11d7d0>, queue_name='default', actor_...
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/dramatiq/actor.py", line 177, in __call__
stacks-fief-1  |     return self.fn(*args, **kwargs)
stacks-fief-1  |            โ”‚    โ”‚   โ”‚       โ”” {}
stacks-fief-1  |            โ”‚    โ”‚   โ”” ('0d4e8575-eb5b-48f4-95c1-2a50e9dcf08e', '74272c99-3631-4cba-a61f-f11ba3c88275', '9V5SB4')
stacks-fief-1  |            โ”‚    โ”” <fief.tasks.email_verification.OnEmailVerificationRequestedTask object at 0x7fa9ea11d7d0>
stacks-fief-1  |            โ”” Actor(<fief.tasks.email_verification.OnEmailVerificationRequestedTask object at 0x7fa9ea11d7d0>, queue_name='default', actor_...
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/fief/tasks/base.py", line 108, in __call__
stacks-fief-1  |     result = runner.run(self.run(*args, **kwargs))
stacks-fief-1  |              โ”‚      โ”‚   โ”‚    โ”‚    โ”‚       โ”” {}
stacks-fief-1  |              โ”‚      โ”‚   โ”‚    โ”‚    โ”” ('0d4e8575-eb5b-48f4-95c1-2a50e9dcf08e', '74272c99-3631-4cba-a61f-f11ba3c88275', '9V5SB4')
stacks-fief-1  |              โ”‚      โ”‚   โ”‚    โ”” <function OnEmailVerificationRequestedTask.run at 0x7fa9e9fc2e80>
stacks-fief-1  |              โ”‚      โ”‚   โ”” <fief.tasks.email_verification.OnEmailVerificationRequestedTask object at 0x7fa9ea11d7d0>
stacks-fief-1  |              โ”‚      โ”” <function Runner.run at 0x7fa9f0652fc0>
stacks-fief-1  |              โ”” <asyncio.runners.Runner object at 0x7fa9da1c5d10>
stacks-fief-1  |   File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
stacks-fief-1  |     return self._loop.run_until_complete(task)
stacks-fief-1  |            โ”‚    โ”‚                        โ”” <Task finished name='Task-107' coro=<OnEmailVerificationRequestedTask.run() done, defined at /usr/local/lib/python3.11/site-p...
stacks-fief-1  |            โ”‚    โ”” None
stacks-fief-1  |            โ”” <asyncio.runners.Runner object at 0x7fa9da1c5d10>
stacks-fief-1  |   File "/usr/local/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
stacks-fief-1  |     return future.result()
stacks-fief-1  |            โ”‚      โ”” <method 'result' of '_asyncio.Task' objects>
stacks-fief-1  |            โ”” <Task finished name='Task-107' coro=<OnEmailVerificationRequestedTask.run() done, defined at /usr/local/lib/python3.11/site-p...
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/fief/tasks/email_verification.py", line 41, in run
stacks-fief-1  |     subject = await email_subject_renderer.render(
stacks-fief-1  |                     โ”‚                      โ”” <function EmailSubjectRenderer.render at 0x7fa9e9fc0540>
stacks-fief-1  |                     โ”” <fief.services.email_template.renderers.EmailSubjectRenderer object at 0x7fa9da057b90>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/fief/services/email_template/renderers.py", line 144, in render
stacks-fief-1  |     subject_template_object = jinja_environment.get_template(type.value)
stacks-fief-1  |                               โ”‚                 โ”‚            โ”‚    โ”” <enum.property object at 0x7fa9f1107090>
stacks-fief-1  |                               โ”‚                 โ”‚            โ”” <EmailTemplateType.VERIFY_EMAIL: 'VERIFY_EMAIL'>
stacks-fief-1  |                               โ”‚                 โ”” <function Environment.get_template at 0x7fa9ea1a32e0>
stacks-fief-1  |                               โ”” <jinja2.sandbox.ImmutableSandboxedEnvironment object at 0x7fa9da057c10>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1010, in get_template
stacks-fief-1  |     return self._load_template(name, globals)
stacks-fief-1  |            โ”‚    โ”‚              โ”‚     โ”” None
stacks-fief-1  |            โ”‚    โ”‚              โ”” 'VERIFY_EMAIL'
stacks-fief-1  |            โ”‚    โ”” <function Environment._load_template at 0x7fa9ea1a3240>
stacks-fief-1  |            โ”” <jinja2.sandbox.ImmutableSandboxedEnvironment object at 0x7fa9da057c10>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 969, in _load_template
stacks-fief-1  |     template = self.loader.load(self, name, self.make_globals(globals))
stacks-fief-1  |                โ”‚    โ”‚      โ”‚    โ”‚     โ”‚     โ”‚    โ”‚            โ”” None
stacks-fief-1  |                โ”‚    โ”‚      โ”‚    โ”‚     โ”‚     โ”‚    โ”” <function Environment.make_globals at 0x7fa9ea1a34c0>
stacks-fief-1  |                โ”‚    โ”‚      โ”‚    โ”‚     โ”‚     โ”” <jinja2.sandbox.ImmutableSandboxedEnvironment object at 0x7fa9da057c10>
stacks-fief-1  |                โ”‚    โ”‚      โ”‚    โ”‚     โ”” 'VERIFY_EMAIL'
stacks-fief-1  |                โ”‚    โ”‚      โ”‚    โ”” <jinja2.sandbox.ImmutableSandboxedEnvironment object at 0x7fa9da057c10>
stacks-fief-1  |                โ”‚    โ”‚      โ”” <function BaseLoader.load at 0x7fa9ea1b0e00>
stacks-fief-1  |                โ”‚    โ”” <jinja2.loaders.FunctionLoader object at 0x7fa9da054150>
stacks-fief-1  |                โ”” <jinja2.sandbox.ImmutableSandboxedEnvironment object at 0x7fa9da057c10>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/jinja2/loaders.py", line 126, in load
stacks-fief-1  |     source, filename, uptodate = self.get_source(environment, name)
stacks-fief-1  |                                  โ”‚    โ”‚          โ”‚            โ”” 'VERIFY_EMAIL'
stacks-fief-1  |                                  โ”‚    โ”‚          โ”” <jinja2.sandbox.ImmutableSandboxedEnvironment object at 0x7fa9da057c10>
stacks-fief-1  |                                  โ”‚    โ”” <function FunctionLoader.get_source at 0x7fa9ea1b1580>
stacks-fief-1  |                                  โ”” <jinja2.loaders.FunctionLoader object at 0x7fa9da054150>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/jinja2/loaders.py", line 462, in get_source
stacks-fief-1  |     rv = self.load_func(template)
stacks-fief-1  |          โ”‚    โ”‚         โ”” 'VERIFY_EMAIL'
stacks-fief-1  |          โ”‚    โ”” <fief.services.email_template.renderers.EmailSubjectLoader object at 0x7fa9da055c90>
stacks-fief-1  |          โ”” <jinja2.loaders.FunctionLoader object at 0x7fa9da054150>
stacks-fief-1  |   File "/usr/local/lib/python3.11/site-packages/fief/services/email_template/renderers.py", line 106, in __call__
stacks-fief-1  |     return self.templates_map[name].subject
stacks-fief-1  |            โ”‚    โ”‚             โ”” 'VERIFY_EMAIL'
stacks-fief-1  |            โ”‚    โ”” {'BASE': <fief.models.email_template.EmailTemplate object at 0x7fa9da01f490>, 'WELCOME': <fief.models.email_template.EmailTem...
stacks-fief-1  |            โ”” <fief.services.email_template.renderers.EmailSubjectLoader object at 0x7fa9da055c90>
stacks-fief-1  | 
stacks-fief-1  | KeyError: 'VERIFY_EMAIL'
stacks-fief-1  | 
stacks-fief-1  | 2023-08-18 14:54:19.725 | INFO     | dramatiq.middleware.retries:after_process_message:115 - Retrying message '28957844-9037-41a4-91cb-6649fc8f21e3' in 117985 milliseconds. - {}

Migration is automatic in docker... what do we miss ?

Configuration

  • Cloud or self-hosted: self-hosted
  • If self-hosted, Fief version: 0.26

NotImplementedError when trying to order users by tenant

Describe the bug

When a user tries to orders users by tenant, an internal server error is raised.

To Reproduce

Steps to reproduce the behavior:

  1. Go to Users
  2. Click on the Tenant header in table
  3. See error in Network tab

The underlying API request provoking the error: /users/?limit=10&skip=0&ordering=tenant

Expected behavior

The users should be sorted by tenant.

Configuration

  • Cloud or self-hosted: Both
  • If self-hosted, Fief version: 0.12.14

Additional context

https://sentry.io/organizations/fief/issues/3214285028

Add a setting to allow non-SSL HTTP URL as Redirect URL

Following discussion #230, I think it could be a good idea to have a setting to disable the HTTPS requirement for Client Redirect URL.

In some contexts, like private deployments, it may be useful to disable it. Of course, this would need a proper warning in the related documentation.

Plan:

  • Add a client_redirect_uri_ssl_required to Settings. Defaults to True.
  • Update validate_redirect_uri implementation to account for this parameter.
  • Document the setting in Environment Variables. Add a warning callout to mention it's dangerous to set it to False.

Role update fails to send task to worker

Faulty code:

send_task(
on_role_updated,
str(role.id),
set(map(str, added_permissions)),
set(map(str, deleted_permissions)),
str(workspace.id),
)

set objects are not encodable by the JSON encoder of Dramatiq.

The error is not catched by unit tests because send_task is fully mocked. This needs to be improved as well so we can catch this kind of errors.

Sentry: https://fief.sentry.io/issues/4182696675/events/b382c75c7647401c9c5c0d4770e124d7/

Impossible to authenticate through OAuth Provider when `/login` without a login session

Discussed in https://github.com/orgs/fief-dev/discussions/191

Originally posted by aido-ai May 15, 2023
Hello, I have a new question to ask. After creating a new workspace B on the default workspace (fief), I added a new GitHub oAuth Provider.

However, when I log in through GitHub oAuth on B.ROOTDOMAIN/login (request link: https://b.rootdomain/oauth/authorize?tenant=TENANT_ID&provider=PROVIDER_ID),

I receive an "Invalid login session" error (server log: 2023-05-15 13:53:47.546 | INFO | uvicorn.protocols.http.httptools_impl:send:506 - 10.244.0.94:0 - "GET /oauth/authorize?tenant=TENANT_ID&provider=PROVIDER_ID HTTP/1.1" 400 - {}).

What usually causes this issue? I reviewed the relevant configuration again and didn't find any anomalies.

Thank you!

image

fail to run hatch run dev.server.start

clone the github project and trying to run dev.server.start, seeing following error

~/dev/fief ๎‚ฐ main !2 ๎‚ฐ hatch run dev.server.start ๎‚ฒ โœ” ๎‚ฒ fastapi-users ๎œผ ๎‚ฒ 19:34:29
cmd [1] | hatch run translations.compile
compiling catalog fief/locale/en_US/LC_MESSAGES/messages.po to fief/locale/en_US/LC_MESSAGES/messages.mo
compiling catalog fief/locale/pt_BR/LC_MESSAGES/messages.po to fief/locale/pt_BR/LC_MESSAGES/messages.mo
compiling catalog fief/locale/it_IT/LC_MESSAGES/messages.po to fief/locale/it_IT/LC_MESSAGES/messages.mo
compiling catalog fief/locale/pt_PT/LC_MESSAGES/messages.po to fief/locale/pt_PT/LC_MESSAGES/messages.mo
compiling catalog fief/locale/zh_CN/LC_MESSAGES/messages.po to fief/locale/zh_CN/LC_MESSAGES/messages.mo
compiling catalog fief/locale/es_ES/LC_MESSAGES/messages.po to fief/locale/es_ES/LC_MESSAGES/messages.mo
compiling catalog fief/locale/pl_PL/LC_MESSAGES/messages.po to fief/locale/pl_PL/LC_MESSAGES/messages.mo
compiling catalog fief/locale/fr_FR/LC_MESSAGES/messages.po to fief/locale/fr_FR/LC_MESSAGES/messages.mo
compiling catalog fief/locale/de_DE/LC_MESSAGES/messages.po to fief/locale/de_DE/LC_MESSAGES/messages.mo
cmd [2] | hatch run static.build

build
rollup -c rollup.config.js

./styles/globals.scss โ†’ ./fief/static/admin.css...
(!) The emitted file "admin.css" overwrites a previously emitted file of the same name.
created ./fief/static/admin.css in 1.5s

./styles/globals.scss โ†’ ./fief/static/auth.css...
(!) The emitted file "auth.css" overwrites a previously emitted file of the same name.
created ./fief/static/auth.css in 428ms

./js/code-editor.mjs โ†’ ./fief/static/code-editor.bundle.js...
created ./fief/static/code-editor.bundle.js in 6.6s
cmd [3] | uvicorn --host 0.0.0.0 --port 8000 fief.app:app
Traceback (most recent call last):
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/bin/uvicorn", line 10, in
sys.exit(main())
^^^^^^
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/click/core.py", line 1130, in call
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/uvicorn/main.py", line 403, in main
run(
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/uvicorn/main.py", line 568, in run
server.run()
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/uvicorn/server.py", line 59, in run
return asyncio.run(self.serve(sockets=sockets))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/local/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/uvicorn/server.py", line 66, in serve
config.load()
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/uvicorn/config.py", line 471, in load
self.loaded_app = import_from_string(self.app)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/missa/Library/Application Support/hatch/env/virtual/fief-server/vk1mo804/fief-server/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
module = importlib.import_module(module_str)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/init.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "", line 1206, in _gcd_import
File "", line 1178, in _find_and_load
File "", line 1149, in _find_and_load_unlocked
File "", line 690, in _load_unlocked
File "", line 940, in exec_module
File "", line 241, in _call_with_frames_removed
File "/Users/missa/dev/fief/fief/app.py", line 10, in
from fief.apps import api_app, auth_app, dashboard_app
File "/Users/missa/dev/fief/fief/apps/init.py", line 1, in
from fief.apps.api.app import app as api_app
File "/Users/missa/dev/fief/fief/apps/api/app.py", line 5, in
from fief.apps.api.routers.clients import router as clients_router
File "/Users/missa/dev/fief/fief/apps/api/routers/clients.py", line 5, in
from fief import schemas
File "/Users/missa/dev/fief/fief/schemas/init.py", line 1, in
from fief.schemas import (
File "/Users/missa/dev/fief/fief/schemas/client.py", line 4, in
from fief.models.client import ClientType
File "/Users/missa/dev/fief/fief/models/init.py", line 1, in
from fief.models.admin_api_key import AdminAPIKey
File "/Users/missa/dev/fief/fief/models/admin_api_key.py", line 5, in
from fief.models.base import MainBase
File "/Users/missa/dev/fief/fief/models/base.py", line 3, in
from fief.settings import settings
File "/Users/missa/dev/fief/fief/settings.py", line 196, in
settings = Settings()
^^^^^^^^^^
File "pydantic/env_settings.py", line 39, in pydantic.env_settings.BaseSettings.init
File "pydantic/main.py", line 341, in pydantic.main.BaseModel.init
pydantic.error_wrappers.ValidationError: 4 validation errors for Settings
secret
field required (type=value_error.missing)
encryption_key
field required (type=value_error.missing)
fief_client_id
field required (type=value_error.missing)
fief_client_secret
field required (type=value_error.missing)

500 Internal Server Error while using Admin REST API

Describe the bug

Fief responds with "500 Internal Server Error" while using different Admin REST API from a script.

To Reproduce

Steps to reproduce the behavior:

  1. Start Fief instance with one default tenant, one default client, one Admin API Key
  2. Execute a script doing the following:
    • GET /tenants/ # Get default tenant id
    • POST /permissions/ # Create permission1
    • POST /permissions/ # Create permission2
    • POST /users/ # Create user1
    • POST /users/ # Create user2
    • POST /users/{user_id1}/permissions # Assign permission1 to user1
    • POST /users/{user_id2}/permissions # Assign permission2 to user2
      Assuming that requests have all needed and correct POST payloads, headers and Authorization Bearer.

Expected behavior

No "500 Internal server error" responses from Fief.

Configuration

self-hosted, Fief version: 0.24.2

Additional context

The error is non-deterministic, it's not related to any particular request, any request can return 500.
When I added 1 second delay between requests, everything went OK. You can see the successful log below.

xxx@xxx:/opt/src# fief run-server --port 8001 2>&1
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
Main Fief workspace already exists
Main Fief user already exists
2023-05-02 15:08:24.725 | INFO     | fief.lifespan:lifespan:31 - Fief Server started - {"version": "0.24.2"}
INFO:     127.0.0.1:50620 - "GET /tenants/ HTTP/1.1" 200 OK
INFO:     127.0.0.1:50630 - "POST /permissions/ HTTP/1.1" 201 Created
2023-05-02 15:08:31.188 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:08:31.274 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
INFO:     127.0.0.1:50632 - "POST /permissions/ HTTP/1.1" 201 Created
2023-05-02 15:08:31.636 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:08:31.647 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
INFO:     127.0.0.1:50644 - "POST /users/ HTTP/1.1" 201 Created
2023-05-02 15:08:32.796 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "on_after_register"}
2023-05-02 15:08:32.871 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "on_after_register"}
2023-05-02 15:08:32.877 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:08:32.889 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
INFO:     127.0.0.1:50650 - "POST /users/ HTTP/1.1" 201 Created
2023-05-02 15:08:33.847 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "on_after_register"}
2023-05-02 15:08:33.900 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "on_after_register"}
2023-05-02 15:08:33.921 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:08:33.936 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
INFO:     127.0.0.1:50662 - "POST /users/40284c05-9b18-431d-a2ef-b9f1707d76d3/permissions HTTP/1.1" 201 Created
2023-05-02 15:08:34.871 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:08:34.886 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
INFO:     127.0.0.1:50668 - "POST /users/90e4cecd-7898-43a3-84d6-feacdeebaab6/permissions HTTP/1.1" 201 Created
2023-05-02 15:08:35.884 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:08:35.912 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
^C

Without delays, however, I could not execute my script fully, not getting 500 at some of the requests. The log in this case looks like this:

xxx@xxx:/opt/src# fief run-server --port 8001 2>&1
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
Main Fief workspace already exists
Main Fief user already exists
2023-05-02 15:12:02.562 | INFO     | fief.lifespan:lifespan:31 - Fief Server started - {"version": "0.24.2"}
INFO:     127.0.0.1:60742 - "GET /tenants/ HTTP/1.1" 200 OK
INFO:     127.0.0.1:52424 - "POST /permissions/ HTTP/1.1" 201 Created
INFO:     127.0.0.1:52434 - "POST /permissions/ HTTP/1.1" 201 Created
INFO:     127.0.0.1:52450 - "POST /users/ HTTP/1.1" 201 Created
2023-05-02 15:12:08.245 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
INFO:     127.0.0.1:52456 - "POST /users/ HTTP/1.1" 500 Internal Server Error
2023-05-02 15:12:08.344 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
2023-05-02 15:12:08.351 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:12:08.381 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
2023-05-02 15:12:08.402 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:12:08.437 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
2023-05-02 15:12:08.443 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "on_after_register"}
2023-05-02 15:12:08.519 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "on_after_register"}
^C

xxx@xxx:/opt/src# fief run-server --port 8001 2>&1
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
Main Fief workspace already exists
Main Fief user already exists
2023-05-02 15:36:08.331 | INFO     | fief.lifespan:lifespan:31 - Fief Server started - {"version": "0.24.2"}
INFO:     127.0.0.1:44862 - "GET /tenants/ HTTP/1.1" 200 OK
INFO:     127.0.0.1:44870 - "POST /permissions/ HTTP/1.1" 201 Created
INFO:     127.0.0.1:44874 - "POST /permissions/ HTTP/1.1" 500 Internal Server Error
2023-05-02 15:36:12.437 | INFO     | fief.tasks.base:__call__:117 - Start task - {"task": "trigger_webhooks"}
2023-05-02 15:36:12.511 | INFO     | fief.tasks.base:__call__:119 - Done task - {"task": "trigger_webhooks"}
^C

It looks like, there is a race related to webhooks somewhere.

pydantic.error_wrappers.ValidationError

Describe the bug

I am following the quick-start instructions at https://docs.fief.dev/self-hosting/quickstart/

To Reproduce

Steps to reproduce the behavior:
docker run -it --rm ghcr.io/fief-dev/fief:latest fief quickstart --docker

Expected behavior

The command will ask you to give an email address for the first admin user. It'll be automatically created when starting the server.

Configuration

  • Cloud or self-hosted: self-hosted
  • If self-hosted, Fief version: v0.26.1 (latest)

Additional context

Actual output:

% docker run -it --rm ghcr.io/fief-dev/fief:latest fief quickstart --docker
Unable to find image 'ghcr.io/fief-dev/fief:latest' locally
latest: Pulling from fief-dev/fief
4ee097f9a366: Pull complete
493e98a6d531: Pull complete
ed400aec434d: Pull complete
a18610e9d04b: Pull complete
195bd9e1cc4c: Pull complete
942bc5ab9ce1: Pull complete
c56efdd7dd86: Pull complete
daf9da8eda35: Pull complete
Digest: sha256:fe7fdcb9366ab2d5afcccc4569c4c117648bee68215baf031173f9cf1c301de0
Status: Downloaded newer image for ghcr.io/fief-dev/fief:latest
/usr/local/lib/python3.11/site-packages/pydantic/env_settings.py:289: UserWarning: directory "/run/secrets" does not exist
  warnings.warn(f'directory "{secrets_path}" does not exist')
Traceback (most recent call last):
  File "/usr/local/bin/fief", line 5, in <module>
    from fief.cli import app
  File "/usr/local/lib/python3.11/site-packages/fief/cli.py", line 20, in <module>
    from fief.services.user_manager import InvalidPasswordError, UserAlreadyExistsError
  File "/usr/local/lib/python3.11/site-packages/fief/services/user_manager.py", line 9, in <module>
    from fief import schemas
  File "/usr/local/lib/python3.11/site-packages/fief/schemas/__init__.py", line 1, in <module>
    from fief.schemas import (
  File "/usr/local/lib/python3.11/site-packages/fief/schemas/client.py", line 4, in <module>
    from fief.models.client import ClientType
  File "/usr/local/lib/python3.11/site-packages/fief/models/__init__.py", line 1, in <module>
    from fief.models.admin_api_key import AdminAPIKey
  File "/usr/local/lib/python3.11/site-packages/fief/models/admin_api_key.py", line 5, in <module>
    from fief.models.base import MainBase
  File "/usr/local/lib/python3.11/site-packages/fief/models/base.py", line 3, in <module>
    from fief.settings import settings
  File "/usr/local/lib/python3.11/site-packages/fief/settings.py", line 199, in <module>
    settings = Settings()
               ^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pydantic/env_settings.py", line 39, in __init__
    super().__init__(
  File "/usr/local/lib/python3.11/site-packages/pydantic/main.py", line 341, in __init__
    raise validation_error
pydantic.error_wrappers.ValidationError: 4 validation errors for Settings
secret
  field required (type=value_error.missing)
encryption_key
  field required (type=value_error.missing)
fief_client_id
  field required (type=value_error.missing)
fief_client_secret
  field required (type=value_error.missing)

Tokens cleanup task fails when connecting to an outdated database

Describe the bug

The tokens cleanup task works by iterating over each database to remove the expired tokens. On external databases, it may happen that the schema is not up-to-date and provoke an error, stopping the whole operation.

Expected behavior

The task should silently discard outdated databases. Maybe add a log warning.

Configuration

  • Cloud or self-hosted: Both
  • If self-hosted, Fief version: 0.16.7

Additional context

https://sentry.io/share/issue/c4914db1f8034389a5a4f346e34440cf/

using fief with mysql planetscale

Describe the bug

when creating a new workspace and connecting to planetscale
i get this error
(pymysql.err.OperationalError) (1105, 'create database is not supported') [SQL: CREATE SCHEMA 988150ae-da92-4eae-9a45-6cf8a843741f] (Background on this error at: https://sqlalche.me/e/20/e3q8)

To Reproduce

Steps to reproduce the behavior:

  1. Go to 'create new work space'
  2. connect to the db with the giving info from planetscale with ssl required
  3. click on ('test connection)
  4. Click on 'create the work space '
  5. See error

Expected behavior

this prevent the workspace from being created

Configuration

  • Cloud or self-hosted: Cloud
  • If self-hosted, Fief version:
  • self-hosted: 0.25.2

invalid openapi admin schema

Describe the bug

validation failed for admin schema
tested here https://apitools.dev/swagger-parser/online/#
also open api generator fail on client generation

looks like missing refs

openapi generator

2023-03-11 20:16:28,311 [10348599] SEVERE - #us.jimschubert.intellij.openapitools.events.GenerationNotificationManager - There were issues with the specification. The option can be disabled via validateSpec (Maven/Gradle) or --skip-validate-spec (CLI).
 | Error count: 5, Warning count: 0
Errors: 
	-attribute components.schemas.UserFieldConfiguration.items is not of type `object`
	-attribute components.schemas.ClientUpdate.min is unexpected
	-attribute components.schemas.Address.countries is unexpected
	-attribute components.schemas.ClientCreate.min is unexpected
	-attribute components.schemas.UserFieldConfiguration.items is missing

java.lang.Throwable: There were issues with the specification. The option can be disabled via validateSpec (Maven/Gradle) or --skip-validate-spec (CLI).
 | Error count: 5, Warning count: 0
Errors: 
	-attribute components.schemas.UserFieldConfiguration.items is not of type `object`
	-attribute components.schemas.ClientUpdate.min is unexpected
	-attribute components.schemas.Address.countries is unexpected
	-attribute components.schemas.ClientCreate.min is unexpected
	-attribute components.schemas.UserFieldConfiguration.items is missing

swagger validator

Swagger schema validation failed.
  #/paths/~1clients~1/get/parameters/2/schema/exclusiveMinimum must be boolean
  #/paths/~1clients~1/get/parameters/2/schema must have required property '$ref'
  #/paths/~1clients~1/get/parameters/2/schema must match exactly one schema in oneOf
  #/paths/~1clients~1/get/parameters/2 must have required property '$ref'
  #/paths/~1clients~1/get/parameters/2 must match exactly one schema in oneOf
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/authorization_code_lifetime_seconds must NOT have additional properties
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/authorization_code_lifetime_seconds must have required property '$ref'
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/authorization_code_lifetime_seconds must match exactly one schema in oneOf
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/access_id_token_lifetime_seconds must NOT have additional properties
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/access_id_token_lifetime_seconds must have required property '$ref'
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/access_id_token_lifetime_seconds must match exactly one schema in oneOf
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/refresh_token_lifetime_seconds must NOT have additional properties
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/refresh_token_lifetime_seconds must have required property '$ref'
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema/properties/refresh_token_lifetime_seconds must match exactly one schema in oneOf
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema must have required property '$ref'
  #/paths/~1clients~1/post/requestBody/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1clients~1/post/requestBody must have required property '$ref'
  #/paths/~1clients~1/post/requestBody must match exactly one schema in oneOf
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/authorization_code_lifetime_seconds must NOT have additional properties
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/authorization_code_lifetime_seconds must have required property '$ref'
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/authorization_code_lifetime_seconds must match exactly one schema in oneOf
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/access_id_token_lifetime_seconds must NOT have additional properties
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/access_id_token_lifetime_seconds must have required property '$ref'
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/access_id_token_lifetime_seconds must match exactly one schema in oneOf
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/refresh_token_lifetime_seconds must NOT have additional properties
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/refresh_token_lifetime_seconds must have required property '$ref'
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema/properties/refresh_token_lifetime_seconds must match exactly one schema in oneOf
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema must have required property '$ref'
  #/paths/~1clients~1{id}/patch/requestBody/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1clients~1{id}/patch/requestBody must have required property '$ref'
  #/paths/~1clients~1{id}/patch/requestBody must match exactly one schema in oneOf
  #/paths/~1email-templates~1/get/parameters/0/schema/exclusiveMinimum must be boolean
  #/paths/~1email-templates~1/get/parameters/0/schema must have required property '$ref'
  #/paths/~1email-templates~1/get/parameters/0/schema must match exactly one schema in oneOf
  #/paths/~1email-templates~1/get/parameters/0 must have required property '$ref'
  #/paths/~1email-templates~1/get/parameters/0 must match exactly one schema in oneOf
  #/paths/~1oauth-providers~1/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1oauth-providers~1/get/parameters/1/schema must have required property '$ref'
  #/paths/~1oauth-providers~1/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1oauth-providers~1/get/parameters/1 must have required property '$ref'
  #/paths/~1oauth-providers~1/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1permissions~1/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1permissions~1/get/parameters/1/schema must have required property '$ref'
  #/paths/~1permissions~1/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1permissions~1/get/parameters/1 must have required property '$ref'
  #/paths/~1permissions~1/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1roles~1/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1roles~1/get/parameters/1/schema must have required property '$ref'
  #/paths/~1roles~1/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1roles~1/get/parameters/1 must have required property '$ref'
  #/paths/~1roles~1/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1tenants~1/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1tenants~1/get/parameters/1/schema must have required property '$ref'
  #/paths/~1tenants~1/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1tenants~1/get/parameters/1 must have required property '$ref'
  #/paths/~1tenants~1/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1users~1/get/parameters/0/schema/exclusiveMinimum must be boolean
  #/paths/~1users~1/get/parameters/0/schema must have required property '$ref'
  #/paths/~1users~1/get/parameters/0/schema must match exactly one schema in oneOf
  #/paths/~1users~1/get/parameters/0 must have required property '$ref'
  #/paths/~1users~1/get/parameters/0 must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country must NOT have additional properties
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country/type must be equal to one of the allowed values
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/0 must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/1/type must be equal to one of the allowed values
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/1 must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties/anyOf/1 must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties must be boolean
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields/additionalProperties must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/fields must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results/items must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema/properties/results must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200/content/application~1json/schema must have required property '$ref'
  #/paths/~1users~1/get/responses/200/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1users~1/get/responses/200 must have required property '$ref'
  #/paths/~1users~1/get/responses/200 must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must NOT have additional properties
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country/type must be equal to one of the allowed values
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must have required property '$ref'
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0 must have required property '$ref'
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1/type must be equal to one of the allowed values
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1 must have required property '$ref'
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1 must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties must have required property '$ref'
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties must be boolean
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields/additionalProperties must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields must have required property '$ref'
  #/paths/~1users~1/post/responses/201/content/application~1json/schema/properties/fields must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201/content/application~1json/schema must have required property '$ref'
  #/paths/~1users~1/post/responses/201/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1users~1/post/responses/201 must have required property '$ref'
  #/paths/~1users~1/post/responses/201 must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must NOT have additional properties
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country/type must be equal to one of the allowed values
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0 must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1/type must be equal to one of the allowed values
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1 must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1 must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties must be boolean
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields/additionalProperties must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema/properties/fields must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1users~1{id}/get/responses/200 must have required property '$ref'
  #/paths/~1users~1{id}/get/responses/200 must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must NOT have additional properties
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country/type must be equal to one of the allowed values
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0/properties/country must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0 must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1/type must be equal to one of the allowed values
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1 must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties/anyOf/1 must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties must be boolean
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields/additionalProperties must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema/properties/fields must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1users~1{id}/patch/responses/200 must have required property '$ref'
  #/paths/~1users~1{id}/patch/responses/200 must match exactly one schema in oneOf
  #/paths/~1users~1{id}~1permissions/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1users~1{id}~1permissions/get/parameters/1/schema must have required property '$ref'
  #/paths/~1users~1{id}~1permissions/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1users~1{id}~1permissions/get/parameters/1 must have required property '$ref'
  #/paths/~1users~1{id}~1permissions/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1users~1{id}~1roles/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1users~1{id}~1roles/get/parameters/1/schema must have required property '$ref'
  #/paths/~1users~1{id}~1roles/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1users~1{id}~1roles/get/parameters/1 must have required property '$ref'
  #/paths/~1users~1{id}~1roles/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1users~1{id}~1oauth-accounts/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1users~1{id}~1oauth-accounts/get/parameters/1/schema must have required property '$ref'
  #/paths/~1users~1{id}~1oauth-accounts/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1users~1{id}~1oauth-accounts/get/parameters/1 must have required property '$ref'
  #/paths/~1users~1{id}~1oauth-accounts/get/parameters/1 must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/parameters/0/schema/exclusiveMinimum must be boolean
  #/paths/~1user-fields~1/get/parameters/0/schema must have required property '$ref'
  #/paths/~1user-fields~1/get/parameters/0/schema must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/parameters/0 must have required property '$ref'
  #/paths/~1user-fields~1/get/parameters/0 must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices/items must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/default must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration/properties/default must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items/properties/configuration must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema/properties/results must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1user-fields~1/get/responses/200 must have required property '$ref'
  #/paths/~1user-fields~1/get/responses/200 must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/default must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration/properties/default must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema/properties/configuration must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/requestBody must have required property '$ref'
  #/paths/~1user-fields~1/post/requestBody must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices/items must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/default must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration/properties/default must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema/properties/configuration must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1user-fields~1/post/responses/201 must have required property '$ref'
  #/paths/~1user-fields~1/post/responses/201 must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/default must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration/properties/default must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema/properties/configuration must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/requestBody must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/requestBody must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices/items/items must be object
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices/items must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/default must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration/properties/default must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema/properties/configuration must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200/content/application~1json/schema must match exactly one schema in oneOf
  #/paths/~1user-fields~1{id}/patch/responses/200 must have required property '$ref'
  #/paths/~1user-fields~1{id}/patch/responses/200 must match exactly one schema in oneOf
  #/paths/~1webhooks~1/get/parameters/0/schema/exclusiveMinimum must be boolean
  #/paths/~1webhooks~1/get/parameters/0/schema must have required property '$ref'
  #/paths/~1webhooks~1/get/parameters/0/schema must match exactly one schema in oneOf
  #/paths/~1webhooks~1/get/parameters/0 must have required property '$ref'
  #/paths/~1webhooks~1/get/parameters/0 must match exactly one schema in oneOf
  #/paths/~1webhooks~1{id}~1logs/get/parameters/1/schema/exclusiveMinimum must be boolean
  #/paths/~1webhooks~1{id}~1logs/get/parameters/1/schema must have required property '$ref'
  #/paths/~1webhooks~1{id}~1logs/get/parameters/1/schema must match exactly one schema in oneOf
  #/paths/~1webhooks~1{id}~1logs/get/parameters/1 must have required property '$ref'
  #/paths/~1webhooks~1{id}~1logs/get/parameters/1 must match exactly one schema in oneOf
  #/components/schemas/Address/properties/country must NOT have additional properties
  #/components/schemas/Address/properties/country/type must be equal to one of the allowed values
  #/components/schemas/Address/properties/country must have required property '$ref'
  #/components/schemas/Address/properties/country must match exactly one schema in oneOf
  #/components/schemas/Address must have required property '$ref'
  #/components/schemas/Address must match exactly one schema in oneOf
  #/components/schemas/ClientCreate/properties/authorization_code_lifetime_seconds must NOT have additional properties
  #/components/schemas/ClientCreate/properties/authorization_code_lifetime_seconds must have required property '$ref'
  #/components/schemas/ClientCreate/properties/authorization_code_lifetime_seconds must match exactly one schema in oneOf
  #/components/schemas/ClientCreate/properties/access_id_token_lifetime_seconds must NOT have additional properties
  #/components/schemas/ClientCreate/properties/access_id_token_lifetime_seconds must have required property '$ref'
  #/components/schemas/ClientCreate/properties/access_id_token_lifetime_seconds must match exactly one schema in oneOf
  #/components/schemas/ClientCreate/properties/refresh_token_lifetime_seconds must NOT have additional properties
  #/components/schemas/ClientCreate/properties/refresh_token_lifetime_seconds must have required property '$ref'
  #/components/schemas/ClientCreate/properties/refresh_token_lifetime_seconds must match exactly one schema in oneOf
  #/components/schemas/ClientCreate must have required property '$ref'
  #/components/schemas/ClientCreate must match exactly one schema in oneOf
  #/components/schemas/ClientUpdate/properties/authorization_code_lifetime_seconds must NOT have additional properties
  #/components/schemas/ClientUpdate/properties/authorization_code_lifetime_seconds must have required property '$ref'
  #/components/schemas/ClientUpdate/properties/authorization_code_lifetime_seconds must match exactly one schema in oneOf
  #/components/schemas/ClientUpdate/properties/access_id_token_lifetime_seconds must NOT have additional properties
  #/components/schemas/ClientUpdate/properties/access_id_token_lifetime_seconds must have required property '$ref'
  #/components/schemas/ClientUpdate/properties/access_id_token_lifetime_seconds must match exactly one schema in oneOf
  #/components/schemas/ClientUpdate/properties/refresh_token_lifetime_seconds must NOT have additional properties
  #/components/schemas/ClientUpdate/properties/refresh_token_lifetime_seconds must have required property '$ref'
  #/components/schemas/ClientUpdate/properties/refresh_token_lifetime_seconds must match exactly one schema in oneOf
  #/components/schemas/ClientUpdate must have required property '$ref'
  #/components/schemas/ClientUpdate must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices/items must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/default must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration/properties/default must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results/items/properties/configuration must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results/items must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results/items must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_/properties/results must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_/properties/results must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserField_ must have required property '$ref'
  #/components/schemas/PaginatedResults_UserField_ must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country must NOT have additional properties
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country/type must be equal to one of the allowed values
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/0/properties/country must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/0 must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/1/type must be equal to one of the allowed values
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/1 must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties/anyOf/1 must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties must be boolean
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields/additionalProperties must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items/properties/fields must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results/items must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_/properties/results must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_/properties/results must match exactly one schema in oneOf
  #/components/schemas/PaginatedResults_UserRead_ must have required property '$ref'
  #/components/schemas/PaginatedResults_UserRead_ must match exactly one schema in oneOf
  #/components/schemas/UserField/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/UserField/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/UserField/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/components/schemas/UserField/properties/configuration/properties/choices/items must have required property '$ref'
  #/components/schemas/UserField/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/components/schemas/UserField/properties/configuration/properties/choices must have required property '$ref'
  #/components/schemas/UserField/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/components/schemas/UserField/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/components/schemas/UserField/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/components/schemas/UserField/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/UserField/properties/configuration/properties/default must have required property '$ref'
  #/components/schemas/UserField/properties/configuration/properties/default must match exactly one schema in oneOf
  #/components/schemas/UserField/properties/configuration must have required property '$ref'
  #/components/schemas/UserField/properties/configuration must match exactly one schema in oneOf
  #/components/schemas/UserField must have required property '$ref'
  #/components/schemas/UserField must match exactly one schema in oneOf
  #/components/schemas/UserFieldConfiguration/properties/choices/items/items must be object
  #/components/schemas/UserFieldConfiguration/properties/choices/items/items must be object
  #/components/schemas/UserFieldConfiguration/properties/choices/items/items must match exactly one schema in oneOf
  #/components/schemas/UserFieldConfiguration/properties/choices/items must have required property '$ref'
  #/components/schemas/UserFieldConfiguration/properties/choices/items must match exactly one schema in oneOf
  #/components/schemas/UserFieldConfiguration/properties/choices must have required property '$ref'
  #/components/schemas/UserFieldConfiguration/properties/choices must match exactly one schema in oneOf
  #/components/schemas/UserFieldConfiguration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/components/schemas/UserFieldConfiguration/properties/default/anyOf/0 must have required property '$ref'
  #/components/schemas/UserFieldConfiguration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/UserFieldConfiguration/properties/default must have required property '$ref'
  #/components/schemas/UserFieldConfiguration/properties/default must match exactly one schema in oneOf
  #/components/schemas/UserFieldConfiguration must have required property '$ref'
  #/components/schemas/UserFieldConfiguration must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices/items must have required property '$ref'
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices must have required property '$ref'
  #/components/schemas/UserFieldCreate/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/components/schemas/UserFieldCreate/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/components/schemas/UserFieldCreate/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate/properties/configuration/properties/default must have required property '$ref'
  #/components/schemas/UserFieldCreate/properties/configuration/properties/default must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate/properties/configuration must have required property '$ref'
  #/components/schemas/UserFieldCreate/properties/configuration must match exactly one schema in oneOf
  #/components/schemas/UserFieldCreate must have required property '$ref'
  #/components/schemas/UserFieldCreate must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices/items/items must be object
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices/items/items must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices/items must have required property '$ref'
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices/items must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices must have required property '$ref'
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/choices must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/default/anyOf/0/type must be equal to one of the allowed values
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/default/anyOf/0 must have required property '$ref'
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/default/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/default must have required property '$ref'
  #/components/schemas/UserFieldUpdate/properties/configuration/properties/default must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate/properties/configuration must have required property '$ref'
  #/components/schemas/UserFieldUpdate/properties/configuration must match exactly one schema in oneOf
  #/components/schemas/UserFieldUpdate must have required property '$ref'
  #/components/schemas/UserFieldUpdate must match exactly one schema in oneOf
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/0/properties/country must NOT have additional properties
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/0/properties/country/type must be equal to one of the allowed values
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/0/properties/country must have required property '$ref'
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/0/properties/country must match exactly one schema in oneOf
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/0 must have required property '$ref'
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/0 must match exactly one schema in oneOf
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/1/type must be equal to one of the allowed values
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/1 must have required property '$ref'
  #/components/schemas/UserRead/properties/fields/additionalProperties/anyOf/1 must match exactly one schema in oneOf
  #/components/schemas/UserRead/properties/fields/additionalProperties must have required property '$ref'
  #/components/schemas/UserRead/properties/fields/additionalProperties must be boolean
  #/components/schemas/UserRead/properties/fields/additionalProperties must match exactly one schema in oneOf
  #/components/schemas/UserRead/properties/fields must have required property '$ref'
  #/components/schemas/UserRead/properties/fields must match exactly one schema in oneOf
  #/components/schemas/UserRead must have required property '$ref'
  #/components/schemas/UserRead must match exactly one schema in oneOf


o@https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:95564
[211]</parseSwagger/<@https://apitools.dev/swagger-parser/online/js/bundle.min.js:29:45042


o@https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:95564
validateSchema@https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:6322
[1]</SwaggerParser.prototype.validate@https://apitools.dev/swagger-parser/online/js/bundle.min.js:1:3391

To Reproduce

try generate client code (python in my case) from admin open api spec from https://[acc].fief.dev/admin/api/openapi.json

Steps to reproduce the behavior:

  1. try generate client code (python in my case) from admin open api spec

Expected behavior

api spec should be valid

A clear and concise description of what you expected to happen.

Configuration

  • Cloud or self-hosted: Cloud

Additional context

Add any other context about the problem here.

Empty string not accepted as valid user field

Describe the bug

It looks like a user field of type String cannot have an empty string: "ensure this value has at least 1 characters".

To Reproduce

Steps to reproduce the behavior:

  1. Create or update a user field of type String with nothing in the text box.
  2. See error: "ensure this value has at least 1 characters".

Expected behavior

Should empty string be accepted as a valid value for user field of type String?

Configuration

  • Cloud or self-hosted: Cloud

workspace get_by_domain isn't compatible with docker-compose networking

Describe the bug

async def get_by_domain(self, domain: str) -> Workspace | None:

admin api call cannot identify any domain except the given with ROOT_DOMAIN/FIEF_DOMAIN on setup (i.e. localhost is recognized, but inner docker-compose domains are not)

To Reproduce

docker-compose.yml: (note: env secrets are generated for testing and are not my production secrets)

version: '2'

services:
  fief: # generate from the above ^
    image: ghcr.io/fief-dev/fief:latest
    ports:
      - '8000:8000'
    environment:
      - SECRET=XXX
      - FIEF_CLIENT_ID=XXX
      - FIEF_CLIENT_SECRET=XXX
      - ENCRYPTION_KEY=XXX=
      - FIEF_MAIN_ADMIN_API_KEY=ACAB
      - PORT=8000
      - ROOT_DOMAIN=localhost:8000
      - FIEF_DOMAIN=localhost:8000
      - [email protected]
      - [email protected]
      - CSRF_COOKIE_SECURE=False
      - SESSION_DATA_COOKIE_SECURE=False
      - USER_LOCALE_COOKIE_SECURE=False
      - LOGIN_HINT_COOKIE_SECURE=False
      - LOGIN_SESSION_COOKIE_SECURE=False
      - REGISTRATION_SESSION_COOKIE_SECURE=False
      - SESSION_COOKIE_SECURE=False
      - FIEF_ADMIN_SESSION_COOKIE_SECURE=False

  fiefsetup:
    image: curlimages/curl:latest
    depends_on:
      - fief
    restart: "no"
    environment:
      FIEF_API_KEY: "ACAB"
    entrypoint:
      - "/bin/sh"
      - "-c"
      - |
        curl \
        -X GET \
        -H "Authorization: Bearer ${FIEF_API_KEY}" \
        http://fief:8000/admin/api/users/ && echo "\n"

-> run -> get CANT_DETERMINE_VALID_WORKSPACE error

however, run the same curl command from the host machine with http://localhost:8000/admin/api/users/ and it finds the workspace

Expected behavior

I expect it to understand default workspace with whatever root domain it's accessed from

Configuration

self-hosted, as per https://docs.fief.dev/self-hosting/quickstart/ but FIEF_MAIN_ADMIN_API_KEY=ACAB added

Additional context

For context, the main point of why I'm doing this call from inside docker-compose is that I'd like to setup some default schema, namely a field for users, that I'd like to do through admin API automatically on docker setup

ORM error with MySQL backend

Describe the bug

Hi Team, following the self-hosted docker-compose guide with MYSQL database the following error is issued:

fief-server_1  | WorkspaceDatabaseConnectionError: (pymysql.err.OperationalError) (1170, 
fief-server_1  | "BLOB/TEXT column 'message' used in key specification without a key length")
fief-server_1  | [SQL: CREATE INDEX ix_fief_audit_logs_message ON fief_audit_logs (message)]

To Reproduce

Steps to reproduce the behavior:

  1. Create the docker-compose as in the tutorial
  2. Configure the .env file with the data outputted after the configuration container (docker run -it --rm ghcr.io/fief-dev/fief:latest fief quickstart --docker)
  3. Edit .env file and configure a mysql database
  4. Execute docker-compose up

Expected behavior

Fief server should start and migration should be performed with a MySQL backend.

Configuration

  • Cloud or self-hosted: self-hosted
  • If self-hosted, Fief version: ghcr.io/fief-dev/fief:latest (sha256:31bba98a0d386a81ac5a5d4971904d8b1cedcb15c767c71f1ff5727cdc68db04)

Additional context

Here is the full log:

fief-server_1  | โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ locals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚
fief-server_1  | โ”‚ โ”‚                         config = <alembic.config.Config object at        โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  0x7f36ed0281c0>                         โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                     connection = <sqlalchemy.engine.base.Connection      โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  object at 0x7f36ecfd7a00>               โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚ database_connection_parameters = (                                       โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  โ”‚                                       โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  mysql+pymysql://root:***@db:3306/fastaโ€ฆ โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  โ”‚   {}                                  โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  )                                       โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                         engine = Engine(mysql+pymysql://root:***@db:330โ€ฆ โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                    schema_name = 'f6a6bc6b-dd82-4414-b92f-e9c8bfcf8097'  โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                           self = <fief.services.workspace_db.WorkspaceDโ€ฆ โ”‚ โ”‚
fief-server_1  | โ”‚ โ”‚                                  object at 0x7f36ecfd7040>               โ”‚ โ”‚
fief-server_1  | โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚
fief-server_1  | โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
fief-server_1  | WorkspaceDatabaseConnectionError: (pymysql.err.OperationalError) (1170, 
fief-server_1  | "BLOB/TEXT column 'message' used in key specification without a key length")
fief-server_1  | [SQL: CREATE INDEX ix_fief_audit_logs_message ON fief_audit_logs (message)]
fief-server_1  | (Background on this error at: https://sqlalche.me/e/14/e3q8)

errorlog.txt

Fief corrupts the database in case of unsuccessful startup

Describe the bug

Related to #206
After downgrade back to 0.24.2, which was running before, I get "CommandError: Can't locate revision identified by 'deb3261a9742'"

To Reproduce

Steps to reproduce the behavior:
After unsuccessful attempt to upgrade to 0.25.1, I wanted to come back to the version 0.24.2, which was used before.

The Fief 0.24.2 does not start

Expected behavior

Fief shall not leave database in a corrupted state. If it writes something to db upon startup, these changes shall be committed only when startup was successful and rolled back to the initial state otherwise.

Configuration

  • If self-hosted, Fief version: 0.24.2, 0.25.1

Additional context

See the log of 0.24.2 after downgrade from 0.25.1
2023_06_02_fief-0.24.2.log

create/step4 "Invalid default value for 'authenticated_at'"

http://localhost:8000/admin/workspaces/create/step4

(pymysql.err.OperationalError) (1067, "Invalid default value for 'authenticated_at'") [SQL: CREATE TABLE fief_authorization_codes ( id CHAR(36) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT now(), updated_at TIMESTAMP NOT NULL DEFAULT now(), code VARCHAR(255) NOT NULL, c_hash VARCHAR(255) NOT NULL, redirect_uri VARCHAR(2048) NOT NULL, scope JSON NOT NULL, authenticated_at TIMESTAMP NOT NULL, nonce VARCHAR(255), code_challenge VARCHAR(255), code_challenge_method VARCHAR(255), user_id CHAR(36) NOT NULL, client_id CHAR(36) NOT NULL, PRIMARY KEY (id), FOREIGN KEY(client_id) REFERENCES fief_clients (id) ON DELETE CASCADE, FOREIGN KEY(user_id) REFERENCES fief_users (id) ON DELETE CASCADE ) ] (Background on this error at: https://sqlalche.me/e/20/e3q8)

Attached to a different loop error when running server from CLI

Discussed in https://github.com/orgs/fief-dev/discussions/89

It appears that the recent changes in the CLI to automatically create main workspace and user provokes issues with asyncpg (and probably aiomysql).

The problem is that before running uvicorn, we are running functions to create main workspace and user, which open connections to the DB.

After that, when Uvicorn runs, it setups a new event loop ; but the database connections objects are still the same and thus provokes errors.

This is due to our lack of isolation of our main engine and workspace engine manager.

Internal Server Error when running web-application-example

Describe the bug

We get an Internal Server Error when running https://docs.fief.dev/integrate/python/fastapi/#web-application-example. Traceback shows error originated from:
[fief_client/client.py] signed_id_token = jwt.JWT(jwt=id_token_claims, algs=["RS256"], key=jwks)

--> TypeError: Expected JWS, got JWE

To Reproduce

web-application-example, as stated above

Expected behavior

No error

Configuration

  • Cloud or self-hosted: Cloud

Additional context

https://docs.fief.dev/integrate/python/fastapi/#api-example runs fine with no errors

Internal Server Error in sign up with custom user fields

Describe the bug

Internal Server Error is returned submitting the registration form as described below.

To Reproduce

  1. create custom user fields like this
    image
  2. create index.html and callback.html as described here https://docs.fief.dev/integrate/javascript/browser/
  3. start a the web server and go to http://localhost:8000/ supposing index.html is served there
  4. click on Sign up
  5. fill email address and password
  6. don't check the "terms" checkbox
  7. submit the form

Expected behavior

  1. frontend: data validation, prevent the submit
  2. backend: don't crash, return HTTP 400/422

Configuration

  • Cloud or self-hosted: Cloud

Possible issue with setup defaults?

Hi,

Followed the self-hosted docker instructions, supplemented with the information in the quick-start combined with the info in the "self-hosted" section to create a docker-compose file (below), to run an evaluation on a virtualbox controlled VM running ubuntu 21.04. I can't run the app on port 8000 on this set of stacks as I have another application running on it.

version: "3.9"

services:
  fief:
    container_name: fief
    hostname: fief
    image: ghcr.io/fief-dev/fief:latest
    ports:
      - "8001:8000"
    environment:
      - DATABASE_TYPE=POSTGRESQL
      - DATABASE_URL=postgresql://postgres:postgres@postgres-eval_db_1:5432/fief
      - SECRET=XXX
      - FIEF_CLIENT_ID=XXX
      - FIEF_CLIENT_SECRET=XXX
      - ENCRYPTION_KEY=XXX
      - FIEF_DOMAIN=ingress.local:8001
      - FIEF_BASE_URL=http://ingress.local:8001
    volumes:
      - fief-server-data:/data
    restart: unless-stopped
    networks:
      - eval

volumes:
  fief-server-data:
    external: true

networks:
  eval:
    external: true

With the information provided, the fief application DOES seem to set up successfully, with the appropriate schemas created and populated in the remote PostGres container. However, whenever I try to perform my first login by going to

http://ingress.local:8001/admin/

i get a 500 internal server error on a URL redirect of:

http://ingress.local:8001/admin/api/auth/login?redirect_uri=http%3A%2F%2Fingress.local%3A8001%2Fadmin%2F

If i create a vanilla virtualbox Ubuntu 21.04 desktop VM and include the server and build tools, then throw the vanilla fief quickstart and everything it needs inside it, working on a browser INSIDE the VM, going to http://localhost:8000/admin/ works. However, this is not particularly useful for me as my evaluation consists of moving auth for a number of existing containerized apps in *.ingress.local

I'm somewhat familiar with the FastAPI framework and uvicorn/hypercorn, and after exec'ing into the running container, I was able to put uvicorn into debug mode, which spat out the following error stack into docker logs on a repeat of the above event:

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 372, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/debug.py", line 96, in __call__
    raise exc from None
  File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/debug.py", line 93, in __call__
    await self.app(scope, receive, inner_send)
  File "/usr/local/lib/python3.10/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 115, in _run_asgi3
    return await self._run_app(scope, lambda: self.app(scope, receive, send))
  File "/usr/local/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 162, in _run_app
    raise exc from None
  File "/usr/local/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py", line 159, in _run_app
    return await callback()
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 408, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/usr/local/lib/python3.10/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 61, in app
    response = await func(request)
  File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 227, in app
    raw_response = await run_endpoint_function(
  File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 160, in run_endpoint_function
    return await dependant.call(**values)
  File "/usr/local/lib/python3.10/site-packages/fief/apps/admin/routers/auth.py", line 22, in login
    url = await fief.auth_url(
  File "/usr/local/lib/python3.10/site-packages/fief_client/client.py", line 374, in auth_url
    openid_configuration = await self._get_openid_configuration()
  File "/usr/local/lib/python3.10/site-packages/fief_client/client.py", line 463, in _get_openid_configuration
    response = await client.send(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1593, in send
    response = await self._send_handling_auth(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1621, in _send_handling_auth
    response = await self._send_handling_redirects(
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1658, in _send_handling_redirects
    response = await self._send_single_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_client.py", line 1695, in _send_single_request
    response = await transport.handle_async_request(request)
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 352, in handle_async_request
    with map_httpcore_exceptions():
  File "/usr/local/lib/python3.10/contextlib.py", line 153, in __exit__
    self.gen.throw(typ, value, traceback)
  File "/usr/local/lib/python3.10/site-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.ConnectTimeout

Is there anything obvious that i'm missing before i dive deeper into the code?

Thank you and congratulations for what looks like a very polished SSO experience!

"Connection to your database"

Hi, so am trying to follow the instructions in the link https://docs.fief.dev/going-further/byod/#setup-your-database, in my own http://localhost:8000/admin/create-workspace/step3

Database type: PostgreSQL
Host: localhost
Port:5432
Username:XXXX
Password:XXXX
Database name:XXXX
SSL mode: Prefer

(I did not actually use XXX) I have my own database setup and working(I use pgadmin), but whenever i check connection.

Can't connect to the database: (psycopg2.OperationalError) could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432? could not connect to server: Cannot assign requested address Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 5432? (Background on this error at: https://sqlalche.me/e/14/e3q8)

Trailing slash is mandatory for /admin/ endpoint

Describe the bug

When accessing the admin dashboard on http://localhost:8000/admin (no trailing slash), a 404 is raised. The dashboard only responds to http://localhost:8000/admin/ (with trailing slash).

To Reproduce

Steps to reproduce the behavior:

  1. Go to http://localhost:8000/admin
  2. 404 error

Expected behavior

The server should automatically redirect to the path with a trailing slash.

Configuration

  • Cloud or self-hosted: Both

Additional context

This doesn't happen for roots on APIRouter (like /admin/clients or /admin/api/clients) where the redirection is automatically done. We should check if there is a special handling for this in Starlette/FastAPI to find the best solution.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.