Read-only MS Teams CLI for locked-down education tenants — internal chatsvc + EDU APIs over Graph, Python 3.12+ stdlib only.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-29 18:39:47 +02:00
.gitignore chore: ignore pycache 2026-09-28 12:24:35 +02:00
README.md fix: ropc mfa precedence, har client constant, drive guard 2026-09-28 12:48:13 +02:00
teams fix: force utf-8 on stdout/stderr for non-ascii output 2026-09-29 18:39:47 +02:00

teams

CLI for Microsoft Teams (education tenant) over the internal web-client APIs and Microsoft Graph. No app registration, no admin consent. Interactive surface is a one-time device-code approval; everything after that is pure HTTP with silently rotating refresh tokens.

Reads class teams, channel posts, files (including Class Materials), assignments and calendar.

Install

git clone <repo> ~/teams-cli
ln -sf ~/teams-cli/teams ~/.local/bin/teams

Requirements: Python 3.12+ (stdlib only). The tenant ID is hardcoded for my university — change TENANT at the top of the script to yours.

Auth

teams auth password            # username + password, zero UI
teams auth login               # device code, ~15s browser approval

Password login (ROPC) works if the tenant does not force MFA on it; on AADSTS50076 fall back to the device code, which prints a code for https://login.microsoft.com/device. Tokens land in ~/.local/share/teams-cli/auth.json — that file is a live credential for your account, keep it out of sync/backup.

Graph tokens are minted locally from the stored refresh token via the Microsoft Office client. ic3 (posts) and the education assignments API tokens are minted through Teams desktop cross-client redemption. Every mint returns a fresh refresh token, so the chain renews itself — no re-login until the tenant password changes, an admin revokes, or long inactivity.

teams auth import <har> is an alternative bootstrap from a devtools HAR export of teams.cloud.microsoft (useful when device-code is disabled by Conditional Access).

teams auth status shows what is alive.

Usage

teams teams                                  # list class teams
teams channels <team>                        # channels of a team
teams posts <team> [channel] [--limit N]      # read channel posts
teams files <team> [-d DRIVE] [subpath]       # list files
teams files <team> -d "Class Materials" \
    -g "First Midterm/xxx.pdf" -o out.pdf     # download a file
teams assignments [--limit N] [--classes]     # assignments (* = turned in)
teams calendar [--days N] [--past N]          # calendar events

Every command accepts --json for machine-readable output. Team/channel selection is a case-insensitive substring match, diacritics folded (podrska matches podrška).

How it works

  • Teams list/channels/files/calendar: Microsoft Graph, delegated, minted from the refresh token.
  • Channel posts: internal chatsvc (teams.cloud.microsoft/api/chatsvc) with ic3-audience tokens.
  • Assignments: internal education API (assignments.edu.cloud.microsoft/api/v1.0/edu), audience 8f348934-64be-4bb2-bc16-c54c96789f43, minted via Teams desktop client cross-redemption.
  • Device-code bootstrap uses the first-party Microsoft Office client d3590ed6-52b3-4102-aeff-aad2292ab01c; no app registration or admin approval is involved anywhere.

Notes

  • Messaging is read-only; sending goes through the same chatsvc endpoints and can be added.
  • Direct-message chat lists ride the trouter websocket, not REST — not implemented.
  • Graph education permissions are admin-blocked in locked tenants; the internal EDU API sidesteps that.
  • Endpoints are undocumented and can change.
  • Built and tested against a Singidunum University student tenant.