Skip to content

fix(oauth): decode ID token instead of calling Graph API for Microsoft providers#3727

Merged
waleedlatif1 merged 4 commits intostagingfrom
waleedlatif1/sharepoint-oauth-fix
Mar 24, 2026
Merged

fix(oauth): decode ID token instead of calling Graph API for Microsoft providers#3727
waleedlatif1 merged 4 commits intostagingfrom
waleedlatif1/sharepoint-oauth-fix

Conversation

@waleedlatif1
Copy link
Collaborator

Summary

  • External tenant users (e.g. different Azure AD orgs) get a 500 error on SharePoint OAuth callback
  • Root cause: getUserInfo calls Graph API /me without User.Read scope → 403 Forbidden for external users → unhandled throw in better-auth → 500
  • Fix: decode the ID token JWT (standard OIDC approach) instead of calling Graph API /me for all 8 Microsoft providers
  • Added shared getMicrosoftUserInfoFromIdToken() helper, replacing ~187 lines of duplicated Graph API fetch logic with ~39 lines

Type of Change

  • Bug fix

Testing

Tested manually — verified ID token contains all required claims (oid, name, preferred_username) when openid, profile, email scopes are requested

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@cursor
Copy link

cursor bot commented Mar 24, 2026

PR Summary

Medium Risk
Changes Microsoft OAuth login/connection behavior by replacing Graph API /me calls with locally decoded ID token claims, which could affect user identity/email mapping if token claims differ or are missing.

Overview
Fixes Microsoft OAuth callbacks for external-tenant users by stopping Graph API /me calls (which can 403 without consented Graph scopes) and instead deriving getUserInfo from the OIDC idToken.

Adds a shared getMicrosoftUserInfoFromIdToken() helper (JWT payload decode + claim selection for email) and switches all Microsoft providers (microsoft-ad, microsoft-teams, microsoft-excel, microsoft-dataverse, microsoft-planner, outlook, onedrive, sharepoint) to use it, removing duplicated fetch/error-handling logic.

Written by Cursor Bugbot for commit b1bdc76. Configure here.

@vercel
Copy link

vercel bot commented Mar 24, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Mar 24, 2026 0:52am

Request Review

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Email fallback order reversed compared to old code
    • Changed email fallback order from 'preferred_username || email || upn' to 'email || preferred_username || upn' to prioritize actual SMTP mail address over UPN, matching old Graph API behavior.

Create PR

Or push these changes by commenting:

@cursor push bfe50f7c2d
Preview (bfe50f7c2d)
diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts
--- a/apps/sim/lib/auth/auth.ts
+++ b/apps/sim/lib/auth/auth.ts
@@ -106,7 +106,7 @@
   return {
     id: `${payload.oid || payload.sub}-${crypto.randomUUID()}`,
     name: payload.name || 'Microsoft User',
-    email: payload.preferred_username || payload.email || payload.upn,
+    email: payload.email || payload.preferred_username || payload.upn,
     emailVerified: true,
     createdAt: now,
     updatedAt: now,

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 24, 2026

Greptile Summary

This PR fixes a 500 error on Microsoft OAuth callbacks for external tenant users (B2B guests) by replacing Graph API /me calls with direct ID token JWT decoding across all 8 Microsoft OAuth providers. The root cause was that calling /me without a granted User.Read scope returned a 403 for external users, which bubbled up as an unhandled error. The fix is the standard OIDC approach — decode the ID token that is always returned when the openid scope is requested.

Key changes:

  • Adds shared getMicrosoftUserInfoFromIdToken() helper that handles: missing ID token, malformed JWT structure, JSON parse failures, and missing email claims — all with descriptive thrown errors
  • Removes ~187 lines of duplicated Graph API fetch logic across 7 providers and consolidates the existing Dataverse ID-token approach into the new helper
  • Subtly improves email claim priority: emailpreferred_usernameupn (vs. the old Dataverse order of preferred_usernameemailupn), which avoids exposing the external-user #EXT# format when the real email claim is present

Previous review concerns (malformed JSON payload, missing email guard) were addressed in b1bdc76. The lack of JWKS signature verification was acknowledged as out of scope for this fix and is low-risk given tokens arrive directly from Microsoft's token endpoint over TLS.

Confidence Score: 5/5

  • Safe to merge — bug is fixed, refactor is clean, and all prior review concerns have been resolved.
  • The fix is targeted and correct: ID token decoding is the proper OIDC approach when Graph API scopes aren't guaranteed. The shared helper consolidates previously duplicated code with improved error handling. All three previous reviewer concerns (JSON parse safety, email null guard, JWKS verification) were either fixed or explicitly acknowledged as out of scope. No new issues were found in this review pass.
  • No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/auth/auth.ts Replaces 7 duplicated Graph API getUserInfo blocks with a single getMicrosoftUserInfoFromIdToken() helper and migrates all 8 Microsoft OAuth providers to ID token decoding; error handling is thorough and prior review feedback has been incorporated.

Sequence Diagram

sequenceDiagram
    participant User
    participant Sim as Sim OAuth Callback
    participant MS as Microsoft Identity Platform
    participant Helper as getMicrosoftUserInfoFromIdToken()

    User->>MS: Authorize (openid + profile + email scopes)
    MS-->>Sim: Authorization code
    Sim->>MS: Exchange code for tokens
    MS-->>Sim: access_token + id_token (JWT)

    Note over Sim: OLD FLOW (removed)
    Sim-xMS: GET /me (Graph API) — 403 for external users ❌

    Note over Sim: NEW FLOW
    Sim->>Helper: tokens (containing id_token)
    Helper->>Helper: Split JWT, base64-decode payload
    Helper->>Helper: Extract oid/sub, name, email/preferred_username/upn
    Helper-->>Sim: { id, name, email, emailVerified, ... }
    Sim-->>User: OAuth complete ✅
Loading

Reviews (2): Last reviewed commit: "fix(oauth): address review comments - tr..." | Re-trigger Greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review
@greptile review

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@waleedlatif1 waleedlatif1 merged commit dc6f3db into staging Mar 24, 2026
11 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/sharepoint-oauth-fix branch March 24, 2026 01:01
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