Skip to content

fix(auth): honour MS_SCOPES in the OAuth consent request - #75

Open
alperduzgun wants to merge 1 commit into
ryaker:mainfrom
alperduzgun:fix/auth-server-honour-ms-scopes
Open

fix(auth): honour MS_SCOPES in the OAuth consent request#75
alperduzgun wants to merge 1 commit into
ryaker:mainfrom
alperduzgun:fix/auth-server-honour-ms-scopes

Conversation

@alperduzgun

@alperduzgun alperduzgun commented Jul 30, 2026

Copy link
Copy Markdown

Problem

outlook-auth-server.js hardcodes its scope list, while auth/token-storage.js reads MS_SCOPES when refreshing tokens. The two disagree, and the consent request always wins — so setting MS_SCOPES has no effect on what the user actually consents to.

The practical failure: an Azure app registration with Mail.ReadWrite configured still produces a token whose granted scope is Mail.Read only. Every write tool then fails, without any obvious cause:

  • delete-email
  • move-emails
  • draft-email
  • mark-as-read

Reproduced on a personal Microsoft account (MS_TENANT_ID=consumers), commit 95d6ff2:

# .env
MS_SCOPES=offline_access User.Read Mail.ReadWrite Mail.Send Calendars.ReadWrite

# granted token scope after npm run auth-server + consent
User.Read Mail.Read Mail.Send Calendars.Read Calendars.ReadWrite Contacts.Read
                ^^^^^^^^^ requested ReadWrite, got Read
                                                    ^^^^^^^^^^^^ never requested

Note the second half of the bug: Contacts.Read is consented even though nothing asks for it, because it is in the hardcoded list. Users grant more access than the app needs and less than it uses.

Fix

Read MS_SCOPES in AUTH_CONFIG, keeping the existing list as the fallback, so consent and refresh can no longer drift apart. Behaviour is unchanged when MS_SCOPES is unset.

Also documents MS_SCOPES in the README env section, where it was previously undocumented.

Verification

After the fix, with the same .env:

scope: User.Read Mail.ReadWrite Mail.Send Calendars.ReadWrite Calendars.Read Mail.Read Contacts.Read

End-to-end over stdio against a real mailbox:

Tool Before After
list-emails
draft-email ❌ insufficient privileges ✅ draft created
delete-email ❌ insufficient privileges ✅ moved to Deleted Items

(The test draft was deleted as part of the run.)

Credit

Found and fixed while reviewing this server for a Microsoft 365 integration on Jerico — the security review flagged that the consent scopes and the refresh scopes were reading from different sources, which turned out to be a real functional bug rather than a hardening nit.

Summary by CodeRabbit

  • New Features

    • Added support for configuring OAuth scopes with the optional MS_SCOPES environment variable.
    • Configured scopes are now applied consistently during authorization and token refresh.
  • Documentation

    • Updated configuration guidance and important notes to explain MS_SCOPES usage and defaults.

The auth server hardcoded its scope list while token-storage.js reads MS_SCOPES
when refreshing. Setting MS_SCOPES therefore had no effect on consent: the
consented token never carried the requested scopes, and every write tool
(delete-email, move-emails, draft-email, mark-as-read) failed with insufficient
privileges even though the Azure app registration granted Mail.ReadWrite.

Read MS_SCOPES in AUTH_CONFIG with the previous list as fallback, so consent and
refresh can no longer drift apart.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@codeant-ai

codeant-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

User does not have a PR Review subscription.

Go to Team management and add this email to the PR Review subscription.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds optional MS_SCOPES support for OAuth scope configuration, applies it to authorization and token exchange requests, and documents its use for consent and token refresh.

Changes

OAuth scope configuration

Layer / File(s) Summary
Scope override and documentation
outlook-auth-server.js, README.md
AUTH_CONFIG.scopes now parses MS_SCOPES with the existing scopes as the default, while the README documents the space-separated override for consent and token refresh.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately highlights the main auth change: honoring MS_SCOPES during OAuth consent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@outlook-auth-server.js`:
- Around line 46-56: Unify the OAuth scope fallback used by the consent
configuration in outlook-auth-server.js, specifically the scopes definition,
with the shared default list already used by the token refresh path; continue
honoring MS_SCOPES when set. In README.md lines 195-204, retain the
documentation stating that an unset MS_SCOPES preserves defaults only after both
flows reference the same fallback list.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5a618544-327c-4e23-9720-c8e5b84ee94f

📥 Commits

Reviewing files that changed from the base of the PR and between 95d6ff2 and 96ad785.

📒 Files selected for processing (2)
  • README.md
  • outlook-auth-server.js

Comment thread outlook-auth-server.js
Comment on lines +46 to +56
// MS_SCOPES honours the same env var token-storage.js uses for refresh, so the
// consented scopes and the refreshed scopes can't drift apart.
scopes: (process.env.MS_SCOPES || [
'offline_access',
'User.Read',
'Mail.Read',
'Mail.Send',
'Calendars.Read',
'Calendars.ReadWrite',
'Contacts.Read'
],
].join(' ')).split(' ').filter(Boolean),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Unify the fallback OAuth scopes across the consent and refresh paths. MS_SCOPES keeps the paths aligned only when explicitly set; their unset defaults still differ.

  • outlook-auth-server.js#L46-L56: derive the fallback from the same shared default used by token refresh.
  • README.md#L195-L204: retain the “unset preserves defaults” documentation only after both flows use the same fallback list.
📍 Affects 2 files
  • outlook-auth-server.js#L46-L56 (this comment)
  • README.md#L195-L204
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@outlook-auth-server.js` around lines 46 - 56, Unify the OAuth scope fallback
used by the consent configuration in outlook-auth-server.js, specifically the
scopes definition, with the shared default list already used by the token
refresh path; continue honoring MS_SCOPES when set. In README.md lines 195-204,
retain the documentation stating that an unset MS_SCOPES preserves defaults only
after both flows reference the same fallback list.

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