Skip to content

feat(auth): refresh grant + device-flow parity for public clients — retire campus-cli's last raw token calls #87

Description

@nycomp

Follow-up from the 2026-10-04 consumer-workaround retirement sweep (campus-profile#31, campus-classroom#33, campus-cli#29 retired the connections/broker/revoke workarounds from #71–#73). What cannot be retired in consumers yet:

  1. Refresh-token grant for public clients. campus-cli's refresh_access_token (campus_cli/auth/common.py:190-249 @ 7908a3e) still raw-POSTs {auth_url}/oauth/token with grant_type=refresh_token. The grant exists server-side and the auth root's token() accepts it (server-mode _get_token_from_session uses it), but a public client that keeps its own credential store has no library helper of the form "take this stored token, return the refreshed pair".

  2. Device-flow parity. campus-cli's device flow (campus_cli/auth/login.py:41-182) is still raw requests with bespoke handling the library must match before the CLI can delete it: Campus's structured error envelope {"error": {code, message, details.oauth_error}} with flat-OAuth fallback; RFC 8628 §3.5 slow_down (+5s persisted interval); authorization_pending/expired_token/access_denied mapping; network retry on non-final poll attempts. request_device_code()/poll_for_token() exist since fix: bug sweep — timetable envelopes, session cleanup, oauth device flow #70 — migration should start with a parity check of poll_for_token against that list.

  3. (Smaller) JsonClient-level auto-refresh on 401 would let user-session apps stop depending on proactive is_expired() checks (campus-classroom now leans on with_user_session(refresh_if_expired=True); a mid-request 401 after the expiry skew still surfaces to the app).

Suggested shape

  • auth.refresh(stored: OAuthToken) -> OAuthToken (or a pluggable token-store hook on Campus(mode="device")) for (1).
  • A documented parity table (error mapping + slow_down semantics) for (2), then retire the CLI's login.py copies.

Consumer context: campus-cli#29 kept revoke_token best-effort-degradable to False; the same pattern will apply to the refresh/device migrations.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions