Platform
Microsoft Platform
How MyGov integrates with Microsoft 365 — the guiding principle, two integration patterns, and the design for authentication, Exchange resource mailboxes, calendar surfaces, and Entra-based permissions.
| Status | Draft |
| Last updated | — |
| Related |
Layer Location · Calendar & Time · Distribution & Publishing Platform Workflow Engine Module Reservations |
Guiding Principle
MyGov can fully control any data it depends on. If MyGov reads from Microsoft and displays or acts on that data, it must also be able to modify it — either by writing back to Microsoft directly, or by maintaining its own override layer. No feature should be blocked by a ticket to IT or a permission MyGov does not hold.
This rule resolves integration questions without case-by-case debate. It produces two distinct patterns, each appropriate for different data:
| Pattern | How it works | When to use | Examples |
|---|---|---|---|
| Read / Write | MyGov reads from and writes directly to Microsoft via Graph API. Microsoft and MyGov stay in sync; Microsoft is not bypassed. | MyGov owns the operational outcome. The Microsoft artifact exists because MyGov needs it to exist. | Resource mailbox provisioning and management; Entra group membership for module permissions; pushing reservation confirmations to room calendars |
| Seed and Override | MyGov reads from Microsoft to populate its own records, then manages a local override layer. Microsoft remains the source of truth for its own data; MyGov's display or behavior can diverge without IT involvement. | Microsoft owns the record of truth, but MyGov needs control over how it is displayed or used — without changing the underlying Microsoft record. | Employee display name and title (seeded from Entra, overridable in Employee module); resource mailbox display name (seeded from Exchange, overridable in FacilitySpace record) |
The seed-and-override pattern is the same principle as
Employee → EmployeeContact — the record of truth is
separated from what is displayed. Applied at the integration layer it
means MyGov is never fully dependent on the Microsoft record being
correct or current for the public-facing experience.
Two Surfaces, Two Authorities
The core calendar design splits cleanly along audience lines. Trying to use one surface for both has been the source of past reliability and compliance problems.
Citizen-facing
- MyGov calendar component — WCAG 2.1 AA compliant
- ICS / webcal feeds for public subscriptions
- Program and event data owned by MyGov
- No dependency on Exchange availability or formatting
Staff-facing
- Outlook calendar — where staff work, not replaced
- Resource mailboxes for room booking and availability
- MyGov writes TO Exchange; staff see results in Outlook
- Staff subscribe to MyGov ICS feeds — add to Outlook, not embed on pages
Authentication — Entra / Azure AD
All MyGov admin portal staff authentication is handled by Entra (Azure AD) via OAuth 2.0 / OpenID Connect. No credentials are stored in MyGov. The login flow redirects to Microsoft, and MyGov receives an identity token and claims on return.
Claims currently used by the API include basic identity (name, email, object ID) and extended properties for department and position checks. Entra group membership is partially in use for some permission checks but has not been widely rolled out due to the lack of admin portal tooling to manage group membership without IT involvement.
Authorization model
The guiding principle applies here: if MyGov makes authorization decisions based on Entra group membership, MyGov must be able to manage that membership. The design therefore separates two concerns:
- Identity — always Entra. Who the user is, that they are a city employee, their base profile. MyGov does not replicate this.
- Authorization — MyGov manages its own role and permission assignments in the admin portal. Entra group membership can seed an initial role on first login (e.g. a member of the Parks group gets the Parks Editor role), but MyGov admins can adjust permissions without filing an IT request. MyGov writes group membership back to Entra via Graph API when an admin changes a role that maps to a group.
This means the admin portal needs a permission management screen where a MyGov admin can assign module roles to staff members, and those assignments are reflected in both MyGov's own permission records and the corresponding Entra group. Neither system is out of sync, and neither IT nor a developer is in the critical path for a permission change.
Exchange Resource Mailboxes
A FacilitySpace may be backed by an Exchange resource mailbox. The mailbox provides room availability in Outlook's room finder, receives calendar events for confirmed reservations, and gives staff a familiar surface for seeing what is booked in a space.
MyGov is the system of record for the FacilitySpace. Exchange is a sync target —
a staff-facing artifact that MyGov creates, manages, and writes to. The association
is optional per space, and it is independent of citizen-reservability: a staff-only
conference room booked entirely through Outlook still has a resource mailbox, and
that mailbox address is stored on the FacilitySpace record even without a
reservationConfig present.
Two distinct Exchange fields: FacilitySpace.exchangeResourceMailbox
is the room resource identity (Place-level; used for room finder, meeting invite,
Place.ReadWrite.All operations). data.Calendar.exchangeCalendarAddress
is the Exchange calendar that MyGov syncs events to (Calendars.ReadWrite
operations). For a reservable conference room both fields may reference the same
SMTP address, but they represent different Exchange concepts and different Graph API
calls. See Calendar & Time.
Mailbox lifecycle — fully managed by MyGov
IT currently provisions resource mailboxes manually in Exchange Admin. Under this design, the MyGov API takes over that responsibility for spaces managed within MyGov, using Graph API with the appropriate service principal permissions. IT consents to those permissions once; MyGov manages the mailboxes from that point forward.
set reservationConfig
provision mailbox
on FacilitySpace
The admin portal exposes the following mailbox operations:
-
Provision — create a new resource mailbox for a
FacilitySpace. Naming convention is enforced by the API
(e.g.
space-{facilitySlug}-{spaceSlug}@auburnal.gov). Admin-only. - Look up and associate — search existing Exchange mailboxes via Graph API and link one to a FacilitySpace record. Used for spaces that predate this system or were provisioned outside MyGov.
- Add to Outlook — given a staff member, add the space's resource mailbox to their Outlook calendar list via Graph API. Removes the need for staff to find and subscribe manually.
- Write reservation events — when a reservation is confirmed in MyGov, a calendar event is written to the resource mailbox automatically. Staff see it in Outlook.
Naming convention
Resource mailbox addresses follow the pattern
rm_{building-abbreviation}_{roomName}@auburnal.gov —
for example, rm_LIB_ProgramRoom for the Program Room at
the Library. The convention is enforced at provisioning time by the
MyGov API. The display name visible in Outlook's room finder is seeded
from the FacilitySpace name and can be overridden in the FacilitySpace
record without renaming the mailbox address.
Calendar Integration
MyGov → Exchange (write)
MyGov writes to Exchange immediately when a booking or calendar event is created, updated, or deleted in MyGov — not on a scheduled job. The Exchange resource mailbox is the single source of truth for room availability: both staff (via Outlook) and citizens (via the MyGov booking form querying Exchange free/busy) read from it in real time.
Resource mailbox writes:
- A reservation is submitted — write a blocking event to the resource mailbox immediately, regardless of approval status. This ensures the time is unavailable in Outlook and to other MyGov bookings from the moment of submission.
- Staff approve a pending reservation — send a confirmation email to the citizen. The Exchange event is already there.
- Staff deny a pending reservation — cancel the Exchange event and notify the citizen.
- A reservation is cancelled (citizen or staff) — remove the Exchange event immediately.
Shared calendar writes: When any entity in MyGov publishes or
updates an event that maps to a Calendar with an exchangeCalendarAddress,
the write to Exchange happens in the same operation — no scheduled sync needed.
The scheduled job model was rejected for the write direction because it creates
a window where Exchange and MyGov are out of sync.
Exchange → MyGov (read)
Reading from Exchange into MyGov is a deliberate, opt-in flow — not an automatic sync. The use case is staff who author events in Outlook that need to surface on the public website. This should be an intentional action (a "publish to website" step) rather than an automatic mirror, for two reasons:
- Not everything on a staff calendar should be public. Automatic sync risks surfacing internal or private events.
- ICS feeds lose structured data — location links, registration URLs, images. An event authored in Outlook and synced to MyGov arrives as thin iCal fields only.
When this flow is used, the mechanism is Graph API read (not ICS) to preserve as much structure as possible. The result is a native MyGov calendar entry that staff can then enrich with structured fields (facilityId, imageUrl, registrationUrl) in the admin portal.
ICS feeds
MyGov publishes an ICS feed for each calendar. These feeds are:
- Outbound only. Citizens and staff subscribe; nothing writes back via ICS.
- Public-facing. The primary use case is citizens adding a city calendar to their personal calendar app, or staff adding a MyGov calendar to Outlook as a subscription calendar.
- Read-only in Outlook. Staff who subscribe to a MyGov ICS feed see events but cannot edit them. This is intentional — edits happen in the MyGov admin portal, not in Outlook.
Graph API Permissions
The MyGov API service principal requires the following Microsoft Graph application permissions. These are consented once by a tenant admin (the City's IT administrator or the MyGov system owner with appropriate Entra access). No per-request IT involvement is needed after initial consent.
| Permission | Type | Purpose |
|---|---|---|
| Calendars.ReadWrite | Read / Write | Write reservation events to resource mailbox calendars; read calendar data when pulling Exchange events into MyGov |
| Place.ReadWrite.All | Read / Write | Provision and manage Exchange resource mailboxes (rooms); read existing room directory for association |
| Group.ReadWrite.All | Read / Write | Manage Entra group membership for MyGov module permissions; read group membership on login for role seeding |
| User.Read.All | Read | Seed employee records from Entra profile data; look up staff by name or email in admin portal |
| User.ReadWrite.All | Read / Write | Add resource mailboxes to a staff member's Outlook calendar list on their behalf |
| Directory.Read.All | Read | Read department, position, and organizational unit data for role seeding and display in Employee records |
User.ReadWrite.All for adding a mailbox to a specific
user's Outlook, which may require a delegated flow initiated by that
user or an admin acting on their behalf. The exact consent model for
that operation should be confirmed during implementation.
Employee Data — Seed and Override
Employee records in MyGov are seeded from Entra on first login or via a periodic sync. Entra remains the source of truth for identity — the employee's legal name, primary email, and organizational position. MyGov maintains its own override layer for fields that need to differ on the public-facing website:
- Display name (may differ from legal name)
- Job title as shown to the public (may differ from HR title)
- Contact phone and email shown on pages (may be a department line, not a personal address)
- Photo
- Whether the employee is shown publicly at all
The EmployeeContact record (see Distribution & Publishing) carries the public-facing values. The Employee record carries the Entra-seeded values plus the overrides. Neither requires an IT request to update.
A periodic sync (ServerJob schedule) refreshes Entra-sourced fields on Employee records — name, email, department — without overwriting locally managed fields. New employees who log in for the first time get an Employee record created automatically.
Audit Findings
Codebase audited: api/Classes/Workflow/Handlers/MSGraphHandler.cs, api/Classes/Services/FacilityBookingService.cs, api/Classes/Services/TokenService.cs, api/Classes/Workflow/Handlers/MSGraphHandler.md
MSGraphHandler registered operations
| Action | Status | Notes |
|---|---|---|
| CreateEvent | BUILT | Creates calendar event for a user or user\CalendarName. Used for room blocking from program sessions. |
| CreateListItem | BUILT | Creates SharePoint list items via Graph |
| SendMail | BUILT | Send email via Graph on behalf of service account or shared mailbox |
| SendTemplate | BUILT | Render HtmlEmail template + send — combines Mail/Merge + MSGraph/SendMail in one action |
| ListUsers | BUILT | Lists Azure AD users with optional filters |
| GetUserPhoto | BUILT | Downloads user profile photos; Target: "all" or specific email/objectId |
| GetAccessToken | BUILT | Acquires token into context for downstream handlers |
| SyncUsersDelta | BUILT | Syncs Azure AD users to local employee table using delta query — the Entra→Employee sync mechanism |
| ProcessMailboxNDRs | BUILT | Polls shared mailbox for bounce messages, updates CampaignRecipient delivery status. Needs ServerJob row + credential to activate. |
IFacilityBookingService — resource mailbox operations
A dedicated service (not a workflow handler) handles all Exchange room operations:
| Method | Status | Notes |
|---|---|---|
| GetScheduleAsync (free/busy) | BUILT | Graph getSchedule endpoint; checks resource mailbox availability for a date |
| CreateBookingAsync (create event) | BUILT | Creates Exchange event on resource mailbox; returns eventId for future cancellation |
| CancelBookingAsync (delete event) | BUILT | Deletes Exchange event by ID from the resource mailbox |
| Provision resource mailbox | NOT STARTED | Design calls for API-driven mailbox provisioning; not yet implemented |
Feature status summary
| Feature | Status | Notes |
|---|---|---|
| Entra auth for staff (JWT bearer) | BUILT | Standard ASP.NET Microsoft Identity Web integration |
| Employee sync from Azure AD (SyncUsersDelta) | BUILT | Delta query sync to local employee table. ServerJob runs this on a schedule. |
| Employee photo sync (GetUserPhoto) | BUILT | Downloads and stores photo to ImagePathSource |
| Resource mailbox read (free/busy) | BUILT | GetScheduleAsync via FacilityBookingService |
| Resource mailbox write (create/cancel events) | BUILT | CreateBookingAsync / CancelBookingAsync via FacilityBookingService |
| NDR processing (ProcessMailboxNDRs) | BUILT | Active — ServerJob and credential configured, ran successfully against first live campaign. |
| Resource mailbox provisioning (create new) | NOT STARTED | Design calls for Place.ReadWrite.All permission and admin UI — not yet built |
| Entra group management (Group.ReadWrite.All) | NOT AUDITED | Design calls for MyGov to manage Entra groups backing portal roles; not audited in this pass. Prerequisite: agree a group naming convention with IT before rollout (e.g. mygov-{module}-{role}). |
| Exchange → MyGov event flow (opt-in publish from Outlook) | DEFERRED | Read direction is complex and deferred. Design is documented (Graph API read, not ICS; staff enriches in admin portal). Until built: Outlook is read-only relative to the public website — must be explicit in staff documentation. |
| Employee sync frequency | CONFIGURED | Sync runs as a scheduled ServerJob via the workflow engine. Frequency is configured in the ServerJob record — no code change needed to adjust the schedule. |
| Teams notifications (TeamsNotifyHandler) | BUILT | Separate handler; posts to Teams channels via incoming webhook or Graph |