โ— LIVE
OpenAI releases GPT-5 APIIndia AI startup raises $120MBitcoin ETF hits record inflowsMeta Llama 4 benchmarks leakedOpenAI releases GPT-5 APIIndia AI startup raises $120MBitcoin ETF hits record inflowsMeta Llama 4 benchmarks leaked
๐Ÿ“… Sat, 21 Mar, 2026โœˆ๏ธ Telegram
AiFeed24

AI & Tech News

๐Ÿ”
โœˆ๏ธ Follow
๐Ÿ Home๐Ÿค–AI๐Ÿ’ปTech๐Ÿš€Startupsโ‚ฟCrypto๐Ÿ”’Security๐Ÿ‡ฎ๐Ÿ‡ณIndiaโ˜๏ธCloud๐Ÿ”ฅDeals
โœˆ๏ธ News Channel๐Ÿ›’ Deals Channel
Home/Cloud & DevOps/How We Stopped Fighting Enterprise Auth and Read Calendars With a URL
โ˜๏ธCloud & DevOps

How We Stopped Fighting Enterprise Auth and Read Calendars With a URL

Reading Microsoft 365 calendars from scripts in locked-down enterprise environments โ€” without Graph API, without OAuth, without any authentication at all. We're building an on-call scheduling tool for our platform engineering team. One of its core features: automatically check who's out of office be

โšกQuick SummaryAI generating...
P

Praveen KG

๐Ÿ“… Mar 21, 2026ยทโฑ 12 min readยทDev.to โ†—
โœˆ๏ธ Telegram๐• TweetWhatsApp
๐Ÿ“ก

Original Source

Dev.to

https://dev.to/kgpraveen/how-we-stopped-fighting-enterprise-auth-and-read-calendars-with-a-url-1ang
Read Full โ†—

Reading Microsoft 365 calendars from scripts in locked-down enterprise environments โ€” without Graph API, without OAuth, without any authentication at all.

The Problem

We're building an on-call scheduling tool for our platform engineering team. One of its core features: automatically check who's out of office before assigning someone to the on-call rota. Sounds simple โ€” read a calendar, find OOO events, done.

Except we work inside a large enterprise with a locked-down Microsoft 365 tenant. And reading a calendar programmatically turned out to be the hardest part of the entire project.

What we needed:

  • Read OOO/leave events from team members' Outlook calendars
  • Run it from a script on any engineer's laptop (Mac or Windows)
  • No manual token copying, no browser interactions, no IT tickets
  • Just: run a command, get OOO data

What we assumed: Microsoft Graph API. It's the modern, documented, supported way to read calendars. Every tutorial says "just call /me/calendar/getSchedule". We even identified it as the perfect endpoint โ€” it supports batch queries (20 users per call), returns native out-of-office status, and works with both delegated and app-only permissions.

The API wasn't the problem. Getting a token was.

What We Tried (and Why Everything Failed)

Attempt 1: Azure CLI Token

The obvious approach. We already use az login for other tooling. Microsoft's docs say you can get a Graph token with:

az account get-access-token --resource https://graph.microsoft.com

Result: Blocked. Our tenant's Continuous Access Evaluation (CAE) policies reject CLI-issued tokens for Graph API. The token generates fine but every API call returns 401.

Attempt 2: MSAL Device Code Flow

The "headless-friendly" OAuth flow. Display a code, user opens a browser, authorises, script gets a token.

app = msal.PublicClientApplication(client_id, authority=authority)
flow = app.initiate_device_flow(scopes=["Calendars.Read"])

Result: Blocked. Tenant rejects with AADSTS65002 and AADSTS7000218. The app ID isn't pre-approved and our IT team doesn't approve custom app registrations for internal tools.

Attempt 3: Azure AD App Registration

The "proper" way โ€” register an app in Azure AD, get admin consent for Calendars.ReadBasic, use client credentials flow.

Result: Not attempted. Our IT security team is unlikely to approve a custom app registration requesting calendar read permissions across the organisation. The approval process alone would take weeks, and the answer would probably be no.

Attempt 4: Graph Explorer Token (Manual)

Microsoft's Graph Explorer web tool gives you a token when you sign in. We could copy-paste it into the script.

Result: Works, but impractical. The token expires in ~1 hour. Every team lead or engineer running the tool would need to open Graph Explorer, sign in, copy the token, paste it into the terminal. That's not a tool โ€” that's a chore.

Attempt 5: Browser Cookie Extraction

Our incident management integration works by extracting OAuth tokens from browser cookies using Python's browser_cookie3. Could we do the same for Graph tokens?

import browser_cookie3
cj = browser_cookie3.chrome()

Result: Failed. Graph API access tokens aren't stored in cookies. Microsoft stores them in localStorage and sessionStorage, which browser_cookie3 can't access. We found 159 Microsoft cookies in Chrome โ€” session cookies, SSO cookies, auth cookies โ€” but none of them were Graph API access tokens.

Attempt 6: Headless Browser Automation (Playwright)

If the tokens are in localStorage, we'll use Playwright to launch a browser, inject our SSO cookies, navigate to Outlook, and extract the tokens via JavaScript.

context.add_cookies(chrome_cookies)  # 159 SSO cookies
page.goto("https://outlook.office.com/calendar")
token = page.evaluate("localStorage.getItem('msal.access_token')")

Result: Failed. Microsoft's enterprise SSO is profile-bound. It's not just cookies โ€” it's device certificates, MSAL cache, keychain integration, and Conditional Access Evaluation (CAE) device compliance checks. An isolated Playwright context with injected cookies doesn't satisfy any of these checks. The browser just shows a login page.

Attempt 7: Playwright with Persistent Profile

Launch Playwright with a fresh user data directory and hope the SSO cookies carry over from the system.

Result: Failed. A fresh profile has no SSO state. Microsoft redirects to the login page with no auto-SSO.

Attempt 8: Exchange Web Services (EWS)

The older API. Maybe it has a different, more permissive auth story?

Result: Failed differently. Our on-prem Exchange servers are reachable via Kerberos. But the user's mailbox is in Exchange Online, not on-prem. The org-relationship between on-prem and Exchange Online is misconfigured, so EWS returns "mailbox not found" even though Kerberos auth succeeds.

Attempt 9: Chrome DevTools Protocol

Connect to a running Chrome instance via the DevTools Protocol and extract localStorage directly.

Result: Not tested. Requires restarting Chrome with --remote-debugging-port=9222. Impractical for daily use โ€” you'd have to close all Chrome tabs, relaunch with debug flags, then run the tool.

At this point, we'd spent several sessions across multiple days trying every documented and undocumented approach to reading a calendar from a script. The problem wasn't finding the right API โ€” getSchedule is perfect. The problem was enterprise authentication: a layered defence of CAE, Conditional Access, device compliance, and profile-bound SSO that blocks every automated token acquisition method.

The Breakthrough: A Feature From 2010

While exploring Outlook's calendar sharing settings for an unrelated reason, we noticed something: Publish Calendar.

Outlook has had the ability to publish calendars as ICS (iCalendar) feeds since Exchange 2010. You go to Settings โ†’ Calendar โ†’ Shared calendars โ†’ Publish a calendar, and Outlook generates a URL like:

https://outlook.office365.com/owa/calendar/{calendarId}@domain.com/{secret}/calendar.ics

We opened that URL in a browser. It downloaded an .ics file. We curl'd it from a terminal. It returned data. We tried it from a different machine, without being logged into anything. It returned data.

No authentication. No tokens. No OAuth. No cookies. No browser profile. Nothing.

Just a plain HTTP GET to a URL that returns standard iCalendar data with all the calendar events โ€” including every team member's OOO events.

curl -s "https://outlook.office365.com/owa/calendar/.../calendar.ics"

That's it. That's the entire "authentication" story.

Why This Works

Published calendar ICS feeds are a feature of Exchange, not of Azure AD or the Microsoft identity platform. They predate OAuth 2.0, Graph API, MSAL, and Conditional Access by years. The URL contains a cryptographic secret (the publishSecret path component) that acts as the access control โ€” if you have the URL, you can read the calendar.

This means:

  • No tenant policy blocks it โ€” CAE, Conditional Access, and device compliance don't apply because there's no authentication flow to evaluate
  • No app registration needed โ€” there's no OAuth client involved
  • No token expiry โ€” the URL is permanent until you unpublish
  • Works from anywhere โ€” any machine, any OS, any CI pipeline, any curl command
  • Standard format โ€” iCalendar (RFC 5545) is parseable by every calendar library in every language

The feed is live โ€” every request returns the current calendar state, not a snapshot. When someone creates an OOO event, it appears in the feed within minutes.

Parsing the Data

The ICS feed returns standard VEVENT entries. OOO events typically have summaries like:

SUMMARY:Alex - OOO
SUMMARY:Sam - OOO
SUMMARY:Jordan - A/L
SUMMARY:Morgan - Holiday
SUMMARY:Riley - On leave

With Python's icalendar library:

import urllib.request
from icalendar import Calendar

data = urllib.request.urlopen(ics_url).read()
cal = Calendar.from_ical(data)

for event in cal.walk():
    if event.name == 'VEVENT':
        summary = str(event.get('summary', ''))
        start = event.get('dtstart').dt
        end = event.get('dtend').dt
        # Match OOO patterns: "Name - OOO", "Name on leave", etc.

We parsed our feed and extracted dozens of OOO events covering our full team โ€” from a single URL, with zero authentication, in about 10 lines of Python.

The Approach: One Calendar, One URL

Our team follows the convention of sending OOO calendar events when they're going to be away. These events appear on the team lead's calendar (as accepted invites). So a single person's published calendar contains OOO data for the entire team.

The setup is:

  1. One person publishes their Outlook calendar (one-time, 30-second setup)
  2. The tool fetches the ICS URL (plain HTTP GET)
  3. Parses OOO events with regex pattern matching
  4. Feeds the OOO data into the on-call scheduling tool

For teams where OOO events don't naturally aggregate on one calendar, alternatives include:

  • Microsoft 365 Group: Create a group, everyone adds OOO events to the group calendar, publish the group calendar โ€” one URL
  • Individual feeds: Each person publishes their calendar, tool fetches all URLs

The Irony

We spent days fighting the modern Microsoft identity stack โ€” CAE, MSAL, Conditional Access, device compliance, profile-bound SSO, browser automation. The solution was a feature that Microsoft shipped in Exchange Server 2010, before any of those systems existed.

Published calendar feeds sit at a layer below the modern auth stack. They don't use Azure AD tokens, they don't trigger Conditional Access policies, they don't require device compliance. They're just... URLs.

Sometimes the answer isn't fighting through the front door. It's finding the side entrance that's been open for 16 years.

How to Set This Up

Publishing Your Calendar

  1. Go to outlook.office.com/calendar
  2. Settings (gear icon) โ†’ View all Outlook settings
  3. Calendar โ†’ Shared calendars
  4. Under Publish a calendar, select the calendar
  5. Choose Can view all details
  6. Click Publish
  7. Copy the ICS link

That's your permanent, zero-auth calendar feed URL.

Reading It

# From any machine, no login required
curl -s "https://outlook.office365.com/owa/calendar/.../calendar.ics" | head -50

Parsing OOO Events

pip install icalendar
import urllib.request
from icalendar import Calendar
from datetime import date

url = "https://outlook.office365.com/owa/calendar/.../calendar.ics"
data = urllib.request.urlopen(url).read()
cal = Calendar.from_ical(data)

for event in cal.walk():
    if event.name == "VEVENT":
        summary = str(event.get("summary", ""))
        if any(kw in summary.lower() for kw in ["ooo", "leave", "holiday", "sick"]):
            start = event.get("dtstart").dt
            end = event.get("dtend").dt
            print(f"{start} โ†’ {end}: {summary}")

Security Considerations

The published calendar URL contains a secret in its path. Anyone with the URL can read the calendar. Treat it like an API key:

  • Don't commit it to public repositories
  • Share it only with people who need it
  • Store it in environment variables or secret management
  • You can unpublish at any time to invalidate the URL

The URL doesn't grant write access โ€” it's read-only. And it only exposes the published calendar, not the entire mailbox.

When This Approach Works

This approach is ideal when:

  • Your enterprise tenant blocks Graph API tokens from CLI tools (CAE/Conditional Access)
  • You can't get an Azure AD App Registration approved
  • You need zero-setup, zero-auth calendar reads from scripts or CI pipelines
  • Your team follows a convention of calendar-based OOO announcements
  • You're comfortable with a convention-dependent (not system-enforced) data source

It's less suitable when:

  • You need write access to calendars
  • You need real-time, sub-minute freshness (ICS feeds have a few minutes propagation delay)
  • Your organisation has disabled calendar publishing at the tenant level
  • You need calendar data from people who haven't published their calendars

Closing Thought

The best engineering solutions aren't always the most sophisticated ones. Graph API with getSchedule is technically the right answer โ€” batch queries, native OOF detection, structured response. But "technically right" doesn't matter if you can't get a token.

A URL that returns a text file solved a problem that OAuth 2.0, MSAL, Playwright, and five different authentication strategies couldn't.

The author is a software engineering manager at a large enterprise retailer, building internal developer platform tooling.

Tags:#cloud#dev.to

Found this useful? Share it!

โœˆ๏ธ Telegram๐• TweetWhatsApp

Read the Full Story

Continue reading on Dev.to

Visit Dev.to โ†—

Related Stories

โ˜๏ธ
โ˜๏ธCloud & DevOps

Majority Element

about 2 hours ago

โ˜๏ธ
โ˜๏ธCloud & DevOps

Building a SQL Tokenizer and Formatter From Scratch โ€” Supporting 6 Dialects

about 2 hours ago

โ˜๏ธ
โ˜๏ธCloud & DevOps

Markdown Knowledge Graph for Humans and Agents

about 2 hours ago

Moving Beyond Disk: How Redis Supercharges Your App Performance
โ˜๏ธCloud & DevOps

Moving Beyond Disk: How Redis Supercharges Your App Performance

about 2 hours ago

๐Ÿ“ก Source Details

Dev.to

๐Ÿ“… Mar 21, 2026

๐Ÿ• about 4 hours ago

โฑ 12 min read

๐Ÿ—‚ Cloud & DevOps

Read Original โ†—

Web Hosting

๐ŸŒ Hostinger โ€” 80% Off Hosting

Start your website for โ‚น69/mo. Free domain + SSL included.

Claim Deal โ†’

๐Ÿ“ฌ AiFeed24 Daily

Top 5 AI & tech stories every morning. Join 40,000+ readers.

โœฆ 40,218 subscribers ยท No spam, ever

Cloud Hosting

โ˜๏ธ Vultr โ€” $100 Free Credit

Deploy cloud servers in 25+ locations. From $2.50/mo. No contract.

Claim $100 Credit โ†’
AiFeed24

India's AI-powered tech news hub. Daily coverage of AI, startups, crypto and emerging technology.

โœˆ๏ธ๐Ÿ›’

Topics

Artificial IntelligenceStartups & VCCryptocurrencyCybersecurityCloud & DevOpsIndia Tech

Company

About AiFeed24Write For UsContact

Daily Digest

Top 5 AI stories every morning. 40,000+ readers.

No spam, ever.

ยฉ 2026 AiFeed24 Media.Affiliate Disclosure โ€” We earn commission on qualifying purchases at no extra cost to you.
PrivacyTermsCookies