Third commit in the session-expiration-policy series. Every refresh token
issued from now on carries the policy snapshot in its JWT (in seconds,
for direct Unix math), and every login/OAuth response surfaces both
expiry windows as ISO timestamps. /auth/refresh carries the claims
forward unchanged — including auth_time, which never resets on rotation.
Does NOT yet enforce the absolute cap — that's commit 4, sequenced so
the gate can be reverted independently if pilots hit an edge case.
But the wire is fully populated, and a grandfather path is already in
_refresh_session_tokens for tokens issued before this PR.
Key changes:
- core/security.py: create_refresh_token signature changes to
(user_id, *, auth_time, idle_max_seconds, abs_max_seconds). Adds
resolve_session_policy(account) -> (idle_minutes, absolute_minutes)
applying defaults for NULL overrides.
- schemas/token.py + schemas/oauth.py: Token and OAuthCallbackResponse
gain idle_expires_at + absolute_expires_at (Optional[datetime],
Pydantic emits ISO 8601 UTC strings).
- endpoints/auth.py: new _mint_session_tokens(user, db) and
_refresh_session_tokens(payload, user, db) helpers. /auth/login,
/auth/login/json, and /auth/refresh now route through them. The
refresh endpoint's pre-existing "Refresh token has been revoked"
error normalized to the taxonomy detail "invalid_refresh_token".
- endpoints/oauth.py: both Google and Microsoft callbacks call
_mint_session_tokens; OAuthCallbackResponse carries the expiry
fields through.
- tests: two new cases in test_session_policy.py — login_json embeds
the claims with strict defaults (3d/14d -> 259200/1209600 sec) and
surfaces matching ISO expiry fields; refresh carries auth_time,
idle_max, abs_max forward unchanged across rotation.
35/35 across test_session_policy + test_auth + test_oauth_callbacks +
test_account_invite_lookup + test_account_management.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Second commit in the session-expiration-policy series. Lands the
error-detail taxonomy from §4.10 of the plan; no UI-visible change yet
because the frontend interceptor (commit 7) doesn't read the new detail
strings, but the wire is now ready for it.
Today every /auth/refresh failure returns 401 "Invalid refresh token"
regardless of cause, so the frontend has no way to distinguish "your
session ended for security" from "we don't recognize this token at
all." This commit introduces:
- decode_refresh_token_strict(): wraps jose.jwt.decode and raises a new
IdleTokenExpired exception (from ExpiredSignatureError) so callers
can branch on idle expiry. All other jose failures still propagate
as JWTError. The legacy decode_token() is preserved for access-token,
password-reset, and email-verification paths that don't need the
distinction.
- get_refresh_token_payload(): now maps IdleTokenExpired ->
"session_expired_idle", JWTError and wrong-type tokens ->
"invalid_refresh_token".
- test_session_policy.py: new test file (will accumulate cases across
the series). Three tests for the taxonomy: idle-expired returns
session_expired_idle; wrong type returns invalid_refresh_token; bad
signature returns invalid_refresh_token.
20/20 across test_session_policy + test_auth + test_oauth_callbacks.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: update Google Fonts to Bricolage Grotesque, IBM Plex Sans, JetBrains Mono
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update Tailwind config to Slate & Ice theme colors and fonts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update CSS variables and glass-card utilities for Slate & Ice theme
- Replace all color variables with Slate & Ice palette
- Add glass system vars (--glass-bg, --glass-blur, --shadow-float)
- Replace legacy glass-card with new variable-driven glass classes
- Add breatheGlow, bellWobble, slideDown, fadeInRight keyframes
- Update font references to IBM Plex Sans and Bricolage Grotesque
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: recolor BrandLogo to cyan gradient, split BrandWordmark for gradient Flow text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update TopBar with glassmorphism backdrop and cyan accent styling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update Sidebar with glassmorphism backdrop
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add ambient atmosphere gradient orbs behind app shell
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update QuickStats and SessionsPanel with glass-card styling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add WeeklyCalendar, QuickActions, OpenSessions, RecentActivity dashboard components
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: redesign dashboard layout with calendar, open sessions, and glass-card panels
New layout: greeting → calendar+actions → sessions+stats → activity
Replaces old QuickStats and SessionsPanel with new dashboard components
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace remaining purple hex references with ice-cyan accent
Sweep of hardcoded purple hex values (#818cf8, #6366f1) replaced with
new cyan accent (#06b6d4) in QuickActions, RecentActivity, QuickLaunch,
and SVG brand assets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update CLAUDE.md branding and design system for Slate & Ice Modern
Updated Last Updated date, branding section (fonts, colors, glass
utilities, atmosphere orbs), component styling rules, and Design System
section to reflect the new ice-cyan glassmorphism theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add Slate & Ice Modern design doc and implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: redesign login page with Slate & Ice Modern design system
Apply glassmorphism styling, atmosphere orbs, branded wordmark, and
consistent design tokens to match the updated app shell aesthetic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: raise TopBar z-index so profile dropdown renders above main content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add AI assistant with in-session copilot and standalone chat with RAG
Implements three-phase AI assistant feature:
- Phase 0: RAG infrastructure with pgvector embeddings, Voyage AI integration,
tree chunking service, and semantic search over team's flow library
- Phase 1: In-session copilot panel during flow navigation with contextual
AI help, current step awareness, and suggested related flows
- Phase 2: Standalone AI chat page with persistent conversation history,
pin/delete, and configurable retention policies (account-level)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add account management, email verification, AI fixes, and user guides
- Profile settings, account transfer, delete/leave account flows
- Email verification with JWT tokens and Resend integration
- AI assistant/copilot fixes: markdown rendering, shared RAG helpers,
token tracking, input refocus, model_validate usage
- User guides hub + detail pages with 13 topic guides
- Sidebar and top bar navigation for guides
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent stale chunk errors after deployments
- Set Cache-Control no-cache on index.html in nginx so browsers always
fetch fresh chunk references after a deploy
- Auto-reload on chunk load failures (stale deploy detection) with
loop prevention via sessionStorage
- Show friendly "App Updated" message if auto-reload doesn't resolve it
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add email verification toggle to admin settings
Adds platform-level toggle to enable/disable email verification.
When disabled, the verification banner is hidden and the send
endpoint returns 403.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Phase B addresses 7 high-severity gaps from the permissions audit:
- B1: Enforce tree access check on session start via can_access_tree
- B2: Replace all inline permission helpers with centralized permissions.py
- B3: Fix require_engineer_or_admin to check is_team_admin before role
- B4: Add is_active field on User with enforcement in get_current_active_user
- B5: Add admin user management endpoints (list, get, role, team-admin, deactivate, activate)
- B6: Add rate limiting on auth/invite endpoints via slowapi (disabled in DEBUG)
- B7: Implement refresh token rotation with JTI-based revocation and meaningful logout
Also reduces access token TTL from 15 to 5 minutes and updates CLAUDE.md
with SaaS/MSP context for future planning sessions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>