Skip to content

Automagically connect Thundermail Calendar in FTUE#1544

Merged
davinotdavid merged 18 commits intomainfrom
ftue-automatic-connect-thundermail-calendar
Mar 25, 2026
Merged

Automagically connect Thundermail Calendar in FTUE#1544
davinotdavid merged 18 commits intomainfrom
ftue-automatic-connect-thundermail-calendar

Conversation

@davinotdavid
Copy link
Copy Markdown
Contributor

@davinotdavid davinotdavid commented Feb 26, 2026

Description of the Change

  • Updated docker-compose.yml container ports not to clash with thunderbird-accounts when running locally
  • Added TB_ACCOUNTS_CALDAV_URL env var.
  • Added POST '/caldav/oidc/auth' route to attempt to connect to the CalDAV through the OIDC token.
  • Removed the ConnectYourCalendarThundermailStep as we don't need it anymore + related i18n and enum entries.

Here's the flow:

  • Frontend makes a POST request to /caldav/oidc/auth
  • Appointment's Backend makes a POST request to Account's Backend /appointment/caldav/setup/ passing the APPOINTMENT_CALDAV_SECRET and the current logged in user's OIDC token
  • Account's Backend deletes previously existing App Passwords that match a specific label and creates a new App Password in Stalwart. The password is returned in plain text as we will need it in Appointment's backend to connect to it but it is hashed when saved
  • Appointment's Backend takes the subscriber's email + newly created App Password and connects to the CalDAV server + creates the ExternalConnection entry

Warning

Requires thunderbird/thunderbird-accounts#616 to be merged in first for the best experience on testing this

How to test it

Alright, first of all, this is a joint effort with the thunderbird-accounts repo so make sure you are in the branch appointment-auto-setup-caldav (thunderbird/thunderbird-accounts#469) and you are able to run a docker compose up in both thunderbird-accounts and this branch in Appointment.

Make sure you have the .env var APPOINTMENT_CALDAV_SECRET set in both thunderbird-accounts and this branch to the same values.

Accounts Prerequisites

  • Navigate to the Django Admin in http://localhost:8087/admin and login with user admin@example.org and password admin.
  • Create a Subscription Plan manually in http://localhost:8087/admin/subscription/plan/add/. None of the information here actually matter except for the Product which has to be an active product.
  • Now navigate again to http://localhost:8087/ and you should be redirected to the /subscribe page.
  • Use Paddle's test cards for the checkout.
  • After you are redirected to the dashboard, you are all set!

PS: This whole step is required because only then we will have the authenticate.User model created + the actual Stalwart account to create the App Password.

Steps to test, now in Appointment-land

  • Navigate to http://localhost:8090, if you are redirected to Keycloak, login with the same admin@example.org / admin as before.
  • Go through the FTUE until the step to select which calendar to connect with and select Thundermail Calendar
  • Click Next and see that you are now in the Booking Page step with the Stalwart Calendar pre-selected. All that without manually creating an App Password!

Benefits

  • 1 click configuration for Thundermail Calendar!

Applicable Issues

Fixes #1352

@davinotdavid davinotdavid changed the title [WIP] Automagically connect Thundermail Calendar in FTUE Automagically connect Thundermail Calendar in FTUE Feb 26, 2026
@davinotdavid davinotdavid force-pushed the ftue-automatic-connect-thundermail-calendar branch from 577d577 to f08d7ae Compare February 27, 2026 16:47
@davinotdavid davinotdavid marked this pull request as ready for review March 3, 2026 16:33
Copy link
Copy Markdown
Member

@MelissaAutumn MelissaAutumn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still need to test, but I don't see why this wouldn't work. Thanks!

Needs some code de-duping though 😄

sentry_sdk.set_extra('debug_object', debug_obj)
raise UnexpectedBehaviourWarning(message='Cache incorrect', info=debug_obj)
except UnexpectedBehaviourWarning as ex:
sentry_sdk.capture_exception(ex)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is entirely thunderbird accounts we probably don't need the debug object information. This was just to capture information about failing caldav servers (and I think we've caught all those edge-cases too.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm fair but since I've extracted this into a shared _resolve_caldav_url for both cases, perhaps it wouldn't hurt to leave it?

Comment thread backend/src/appointment/routes/caldav.py Outdated
Comment thread backend/src/appointment/routes/caldav.py Outdated
Comment thread backend/src/appointment/routes/caldav.py Outdated
Comment thread backend/src/appointment/routes/caldav.py Outdated
@davinotdavid
Copy link
Copy Markdown
Contributor Author

@MelissaAutumn sorry for the ping on the re-review but when you have some time, could take another look on this PR? 🙏

Copy link
Copy Markdown
Member

@MelissaAutumn MelissaAutumn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it, but the code looks fine!


oauth2_scheme = OAuth2PasswordBearer(tokenUrl='token', auto_error=False)

async def get_bearer_token(request: Request) -> str | None:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh thanks, but this was okay to punt to another ticket 😅

)

return RedirectResponse(f'{os.getenv("FRONTEND_URL", "http://localhost:8080")}/post-login/{one_time_access_token}')
return RedirectResponse(f'{os.getenv("FRONTEND_URL", "http://localhost:8090")}/post-login/{one_time_access_token}')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a future ticket we should move these to a constant value.

Comment thread backend/.env.example
OIDC_TOKEN_INTROSPECTION_URL=
OIDC_FALLBACK_MATCH_BY_EMAIL=

# Required for Appointment's CalDAV auto-setup, needs to match the one in thunderbird-accounts
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend leaving this blank in the example env.

Comment thread backend/.env.example
TB_ACCOUNTS_CALLBACK=http://localhost:5000/accounts/callback
TB_ACCOUNTS_CLIENT_ID
TB_ACCOUNTS_SECRET
TB_ACCOUNTS_CALDAV_URL=http://host.docker.internal:8081
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important to note this won't work for all docker setups.

case 'oidc':
await ftueStore.moveToStep(FtueStep.ConnectCalendarsThundermail);
case 'oidc': {
isLoading.value = true;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know I don't know if this actually works within the same function call. I know we do it in other places but I don't think I've tested this.

It might work since the await might trigger a dom update eventually, but might be worth a test with a really long delay.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are spot on, it does seem to work because of the await triggering a dom update and Vue batching updates. Tested here with a long delay and it updates the buttons accordingly!

@davinotdavid davinotdavid merged commit f9e0402 into main Mar 25, 2026
8 checks passed
@davinotdavid davinotdavid deleted the ftue-automatic-connect-thundermail-calendar branch March 25, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Connect to CalDAV with OIDC token

2 participants