Skip to content

feat(api): add microsoft sign-in and outlook mailbox sync - #73

Merged
carhartlewis merged 8 commits into
mainfrom
lewis/better-auth-o365
Aug 7, 2026
Merged

feat(api): add microsoft sign-in and outlook mailbox sync#73
carhartlewis merged 8 commits into
mainfrom
lewis/better-auth-o365

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Opened automatically when lewis/better-auth-o365 was pushed.

This pull request is squashed onto main, so its title becomes the commit subject and the changelog line. Make it a Conventional Commitfeat(app): …, fix(api): … — before marking it ready for review, which is when the title is checked.

The type decides the version bump: feat is a minor, fix / perf / refactor / docs are a patch, a trailing ! is a major, and chore / ci / test / build / style release nothing at all.


Summary by cubic

Add Microsoft 365 sign-in and Outlook mail sync, unify Gmail/Calendar with a shared mailbox sync used by both providers, and add a purge for synced mailbox data. Also improve thread handling and streamline CI/releases with auto PR titles, retargeting, and a main→release promotion flow.

  • New Features

    • Microsoft 365 sign-in with Outlook sync via Microsoft Graph (Mail.Read).
    • Shared MailboxModule (tokens, matching, thread writer, HTTP client) now powers Gmail, Calendar, and Outlook; email timeline links to Gmail or Outlook with provider labels.
    • New Microsoft tRPC router and Settings → Connections card; Sign-in and Grant Access support Google and Microsoft.
    • Purge synced mailbox data for both Google and Microsoft; improved thread grouping and cleanup across providers.
    • Unified cron at /internal/sync/mailboxes.
    • CI/Release: pre-push hook runs check-types, lint, and test; PR titles auto-generated from the diff via .github/scripts/pr-title.sh; PRs opened against release are retargeted to main; a promotion workflow opens a PR from main into release; releases run from the release branch.
  • Migration

    • Create an Entra ID app and set MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, and optional MICROSOFT_TENANT_ID (defaults to common); add redirect <API_URL>/api/auth/callback/microsoft.
    • Update cron path to /internal/sync/mailboxes.
    • Run Prisma migration to add outlookMessageId and outlookWebLink.
    • Review .env.example and docs for updated configuration and scope details.

Written for commit 7aad9a7. Summary will update on new commits.

Review in cubic

…pdating environment configurations. Refactor Google sync services to utilize a unified mailbox API client. Update README and .env.example to reflect new authentication options and instructions for Microsoft integration.
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
crm-agent Ready Ready Preview Aug 7, 2026 3:34pm
crm-api Ready Ready Preview Aug 7, 2026 3:34pm
crm-app Ready Ready Preview Aug 7, 2026 3:34pm

Request Review

…l request processes; add pr-title.sh script for automated PR title generation based on Conventional Commit standards; enhance auto-pr workflow to utilize the new script for title management.
@carhartlewis
carhartlewis marked this pull request as ready for review August 7, 2026 15:00
@github-actions github-actions Bot changed the title better auth o365 feat(api): add microsoft sign-in and outlook mailbox sync Aug 7, 2026
…odify auto-pr workflow to create pull requests directly instead of drafts, and enhance title management for better integration with commit subjects and changelog entries.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

6 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/api/src/sync/mailbox-sync.service.ts">

<violation number="1" location="apps/api/src/sync/mailbox-sync.service.ts:89">
P3: Thrown Microsoft syncs are mislabeled as `google_sync` telemetry because this call now reports every provider through a helper with a hard-coded Google error source; make the telemetry event provider-aware so Outlook failures remain distinguishable.</violation>
</file>

<file name="packages/auth/src/env.ts">

<violation number="1" location="packages/auth/src/env.ts:36">
P1: Microsoft sign-in is silently disabled when the API runs through Turborepo with deployment-provided environment variables, because `microsoftCredentials()` sees no client credentials and returns `undefined`; a configured tenant is also ignored. The Microsoft variables should be added to the applicable root and API Turborepo pass-through lists.</violation>
</file>

<file name="apps/api/src/microsoft/microsoft.router.ts">

<violation number="1" location="apps/api/src/microsoft/microsoft.router.ts:34">
P1: An authenticated user can delete another user's Outlook-synced messages when both mailboxes contribute messages to the same thread, because this mutation invokes a purge that removes the whole thread for any matching child message. The purge should delete only the caller's messages and remove a thread only when no messages remain, or otherwise enforce thread ownership.</violation>
</file>

<file name="apps/api/src/mailbox/thread-writer.service.ts">

<violation number="1" location="apps/api/src/mailbox/thread-writer.service.ts:97">
P1: Unknown inbound mail is permanently omitted when it arrives before the user's reply, even with auto-create enabled. Deferring company/contact creation until a reply is reasonable, but the inbound message needs to be retained or replayed once the later outbound message makes the thread eligible; otherwise O365 threads lose their opening messages.</violation>
</file>

<file name="apps/api/src/google/gmail-mime.ts">

<violation number="1" location="apps/api/src/google/gmail-mime.ts:60">
P1: Replies containing multiple message IDs in `In-Reply-To` receive a malformed thread key instead of the first referenced message ID, causing those Gmail messages to split from the shared CRM thread. Extract one message ID from `In-Reply-To` before calling `rootMessageIdFrom` (or make the shared helper parse the field as a list).</violation>
</file>

<file name=".github/workflows/pr-title.yml">

<violation number="1" location=".github/workflows/pr-title.yml:22">
P1: A pull request can change `.github/scripts/pr-title.sh`, and this workflow executes that checked-out file with `GH_TOKEN` and `ANTHROPIC_API_KEY`, creating a credential-exfiltration path. Run only a trusted script from the base commit and fetch PR refs separately, rather than executing code from the PR merge ref.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread apps/api/src/sync/mailbox-sync.service.ts
Comment thread apps/api/src/google/google-connection.service.ts Outdated
Comment thread apps/app/app/(landing)/sign-in/social-sign-in.tsx Outdated
Comment thread packages/auth/src/env.ts
const microsoftCredentials = ():
| { clientId: string; clientSecret: string; tenantId: string }
| undefined => {
const credentials = pair("MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET");

@cubic-dev-ai cubic-dev-ai Bot Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Microsoft sign-in is silently disabled when the API runs through Turborepo with deployment-provided environment variables, because microsoftCredentials() sees no client credentials and returns undefined; a configured tenant is also ignored. The Microsoft variables should be added to the applicable root and API Turborepo pass-through lists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/auth/src/env.ts, line 36:

<comment>Microsoft sign-in is silently disabled when the API runs through Turborepo with deployment-provided environment variables, because `microsoftCredentials()` sees no client credentials and returns `undefined`; a configured tenant is also ignored. The Microsoft variables should be added to the applicable root and API Turborepo pass-through lists.</comment>

<file context>
@@ -2,30 +2,46 @@ import "@crm/env/load";
+const microsoftCredentials = ():
+	| { clientId: string; clientSecret: string; tenantId: string }
+	| undefined => {
+	const credentials = pair("MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET");
+	if (!credentials) return undefined;
+
</file context>
Fix with cubic


@Mutation()
async purgeSyncedData(@Ctx() ctx: AuthedTrpcContext) {
return this.connection.purgeSyncedData(ctx.user.id);

@cubic-dev-ai cubic-dev-ai Bot Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: An authenticated user can delete another user's Outlook-synced messages when both mailboxes contribute messages to the same thread, because this mutation invokes a purge that removes the whole thread for any matching child message. The purge should delete only the caller's messages and remove a thread only when no messages remain, or otherwise enforce thread ownership.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/microsoft/microsoft.router.ts, line 34:

<comment>An authenticated user can delete another user's Outlook-synced messages when both mailboxes contribute messages to the same thread, because this mutation invokes a purge that removes the whole thread for any matching child message. The purge should delete only the caller's messages and remove a thread only when no messages remain, or otherwise enforce thread ownership.</comment>

<file context>
@@ -0,0 +1,60 @@
+
+	@Mutation()
+	async purgeSyncedData(@Ctx() ctx: AuthedTrpcContext) {
+		return this.connection.purgeSyncedData(ctx.user.id);
+	}
+
</file context>
Fix with cubic

Comment thread apps/api/src/microsoft/outlook-sync.service.ts Outdated
error instanceof Error ? error.stack : String(error),
);

syncError({ error, source: row.source });

@cubic-dev-ai cubic-dev-ai Bot Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: Thrown Microsoft syncs are mislabeled as google_sync telemetry because this call now reports every provider through a helper with a hard-coded Google error source; make the telemetry event provider-aware so Outlook failures remain distinguishable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/sync/mailbox-sync.service.ts, line 89:

<comment>Thrown Microsoft syncs are mislabeled as `google_sync` telemetry because this call now reports every provider through a helper with a hard-coded Google error source; make the telemetry event provider-aware so Outlook failures remain distinguishable.</comment>

<file context>
@@ -0,0 +1,116 @@
+					error instanceof Error ? error.stack : String(error),
+				);
+
+				syncError({ error, source: row.source });
+			}
+		}
</file context>
Fix with cubic

Comment thread apps/api/test/auth.e2e.spec.ts Outdated
Comment thread apps/app/app/(app)/[slug]/settings/connections/page.tsx
Comment thread apps/api/src/microsoft/outlook-sync.service.ts
…details on the promotion pull request and the role of the release pull request. Modify release workflow to ensure proper tagging and streamline the promotion of changes from main to release. Enhance CI workflows to better handle pull request retargeting and title management.
…ronment configurations and updating the purge logic for both Google and Microsoft data. Refactor email message handling to improve thread management and ensure proper cleanup of synced data. Introduce new tests for mailbox purging and syncing functionality.
@carhartlewis
carhartlewis merged commit 2a0062f into main Aug 7, 2026
9 checks passed
@carhartlewis
carhartlewis deleted the lewis/better-auth-o365 branch August 7, 2026 15:36
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.

1 participant