Skip to content

[cueweb] Add optional group-based authorization gate#2431

Open
ramonfigueiredo wants to merge 4 commits into
AcademySoftwareFoundation:masterfrom
ramonfigueiredo:cueweb-group-authorization
Open

[cueweb] Add optional group-based authorization gate#2431
ramonfigueiredo wants to merge 4 commits into
AcademySoftwareFoundation:masterfrom
ramonfigueiredo:cueweb-group-authorization

Conversation

@ramonfigueiredo

@ramonfigueiredo ramonfigueiredo commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Related Issues

Main issue:

Issues related to this PR:

Summarize your change.

[cueweb] Add optional group-based authorization gate

Add an opt-in, environment-driven authorization layer that can restrict who may use CueWeb and who may reach the CueCommander administration pages, enforced server-side in a single middleware chokepoint.

  • lib/authz.ts: pure, Edge-safe policy helpers (isAuthzEnabled, isUserAllowed, isUserAdmin, isAdminPath) plus group extraction, all driven by env vars.
  • middleware.ts: requires a signed-in user when the gate is active, then enforces CUEWEB_ALLOWED_GROUPS app-wide and CUEWEB_ADMIN_GROUPS for the CueCommander admin pages and job submission (CueSubmit). Pages redirect to /unauthorized; API routes return 403. Health, metrics, auth, login, unauthorized and static assets are excluded.
  • lib/auth.ts: jwt/session callbacks resolve the user's groups once at sign-in (from the configurable OIDC claim or a credentials/LDAP groups field) and stamp them on the token; the Edge middleware only reads them.
  • app/unauthorized/page.tsx: themed access-denied page.
  • Env knobs (all optional): CUEWEB_AUTHZ_ENABLED (master switch, opt-in, default off), CUEWEB_ALLOWED_GROUPS, CUEWEB_ADMIN_GROUPS, CUEWEB_GROUPS_CLAIM. Documented in .env.example and README.md.

[cueweb/docs]: Document the group-based authorization gate

  • Reference: Add Authorization Variables (CUEWEB_AUTHZ_ENABLED, CUEWEB_ALLOWED_GROUPS, CUEWEB_ADMIN_GROUPS, CUEWEB_GROUPS_CLAIM) with defaults and gate behavior
  • Deploying: Add an Authorization (group-based access control) section with opt-in config and IdP groups-claim requirement
  • Developer guide: Add an Authorization gate section (sign-in resolution vs Edge enforcement, authz helpers, middleware flow, matcher exclusions)
  • User guide: Add a short Restricted access note about the Access denied page

LLM usage disclosure

Parts of this solution's implementation were developed with assistance from Claude Opus.

Add an opt-in, environment-driven authorization layer that can restrict who may use CueWeb and who may reach the CueCommander administration pages, enforced server-side in a single middleware chokepoint.

- lib/authz.ts: pure, Edge-safe policy helpers (isAuthzEnabled, isUserAllowed, isUserAdmin, isAdminPath) plus group extraction, all driven by env vars.
- middleware.ts: requires a signed-in user when the gate is active, then enforces CUEWEB_ALLOWED_GROUPS app-wide and CUEWEB_ADMIN_GROUPS for the CueCommander admin pages and job submission (CueSubmit). Pages redirect to /unauthorized; API routes return 403. Health, metrics, auth, login, unauthorized and static assets are excluded.
- lib/auth.ts: jwt/session callbacks resolve the user's groups once at sign-in (from the configurable OIDC claim or a credentials/LDAP groups field) and stamp them on the token; the Edge middleware only reads them.
- app/unauthorized/page.tsx: themed access-denied page.
- Env knobs (all optional): CUEWEB_AUTHZ_ENABLED (master switch, opt-in, default off), CUEWEB_ALLOWED_GROUPS, CUEWEB_ADMIN_GROUPS, CUEWEB_GROUPS_CLAIM. Documented in .env.example and README.md.
- Reference: Add Authorization Variables (CUEWEB_AUTHZ_ENABLED, CUEWEB_ALLOWED_GROUPS, CUEWEB_ADMIN_GROUPS, CUEWEB_GROUPS_CLAIM) with defaults and gate behavior
- Deploying: Add an Authorization (group-based access control) section with opt-in config and IdP groups-claim requirement
- Developer guide: Add an Authorization gate section (sign-in resolution vs Edge enforcement, authz helpers, middleware flow, matcher exclusions)
- User guide: Add a short Restricted access note about the Access denied page
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an optional group-based authorization gate to CueWeb. A new lib/authz.ts module implements policy helpers that read env configuration and enforce group-based access control. NextAuth JWT and session callbacks stamp group memberships onto the token at sign-in using group extraction logic. A new middleware.ts Edge middleware reads those groups and enforces allow/admin checks, returning 403 for API denials or redirecting to a new /unauthorized page. Four new env vars control the feature: CUEWEB_AUTHZ_ENABLED, CUEWEB_ALLOWED_GROUPS, CUEWEB_ADMIN_GROUPS, and CUEWEB_GROUPS_CLAIM. Supporting documentation is added across README, developer guide, deployment guide, reference docs, and user guide.

Changes

CueWeb group-based authorization gate

Layer / File(s) Summary
Authorization policy module
cueweb/lib/authz.ts
New module defining ADMIN_PATH_PREFIXES for CueCommander and job submission routes, env-config readers (isAuthzEnabled, getGroupsClaim), group normalization from arrays or delimited strings, extractGroups to resolve groups at sign-in from OIDC profile claim or user object, getUserGroups to read stamped token groups, case-insensitive group list intersection helpers, and exported policy functions isUserAllowed/isUserAdmin/isAdminPath.
Group extraction into JWT and session
cueweb/lib/auth.ts
Adds extractGroups import and updates authOptions.callbacks: the jwt callback calls extractGroups during sign-in with profile/user and stamps results onto token.groups; the session callback propagates token.groups to session.groups with empty-array fallback.
Edge middleware enforcement
cueweb/middleware.ts
New withAuth-wrapped middleware that reads getUserGroups from the token and enforces isUserAllowed and conditional isAdminPath/isUserAdmin checks. Returns JSON 403 for /api/* route denials; redirects to /unauthorized for page request denials. Includes config.matcher excluding auth endpoints, health/metrics, login/unauthorized pages, and static assets.
Unauthorized page UI
cueweb/app/unauthorized/page.tsx
New client component rendering an "Access denied" page with explanatory text, a "Back to Monitor Jobs" button (redirects to /), and a "Sign out" button (calls signOut with callback to /login).
Environment and documentation
cueweb/.env.example, cueweb/README.md, docs/_docs/*
Adds four authz env vars to .env.example with defaults, documents the authorization feature in README installation instructions, CueWeb development guide (group resolution and enforcement flow), deployment guide (access control behavior), reference docs (env variable definitions), and user guide (restricted access note).

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant middleware as middleware.ts (Edge)
  participant NextAuth
  participant authz as lib/authz.ts

  Note over Browser,NextAuth: Sign-in flow — group extraction
  Browser->>NextAuth: sign in
  NextAuth->>authz: extractGroups(profile, user)
  authz-->>NextAuth: string[] groups
  NextAuth->>NextAuth: stamp token.groups, session.groups

  Note over Browser,middleware: Subsequent request — enforcement
  Browser->>middleware: GET /some/page
  middleware->>authz: getUserGroups(token)
  authz-->>middleware: string[]
  middleware->>authz: isUserAllowed(groups)
  alt not allowed
    middleware-->>Browser: redirect /unauthorized  OR  JSON 403
  else allowed + isAdminPath
    middleware->>authz: isUserAdmin(groups)
    alt not admin
      middleware-->>Browser: redirect /unauthorized  OR  JSON 403
    else admin
      middleware-->>Browser: NextResponse.next()
    end
  else allowed + not admin path
    middleware-->>Browser: NextResponse.next()
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • [cueweb] Add optional group-based authorization gate #2432: Directly implements the group-based authorization feature described in that enhancement request, including the same env-driven configuration variables, policy enforcement in middleware, JWT/session group stamping, and unauthorized user redirect/403 handling.

Poem

🐰 Hoppin' past the gate today,
My groups must match or I can't stay.
The token carries what I am,
The middleware checks — no spam!
"Access denied" the banner shows,
But those with rights? The pipeline flows. 🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding an optional group-based authorization gate to CueWeb, which is the primary focus across all file modifications.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
cueweb/.env.example (1)

15-27: ⚡ Quick win

Reorder the authz env vars.

dotenv-linter flags this block because CUEWEB_ADMIN_GROUPS / CUEWEB_ALLOWED_GROUPS should sort ahead of CUEWEB_AUTHZ_ENABLED. Reordering keeps the example file lint-clean.

🔧 Suggested reorder
- CUEWEB_AUTHZ_ENABLED=false
- CUEWEB_ALLOWED_GROUPS=
- CUEWEB_ADMIN_GROUPS=
+ CUEWEB_ADMIN_GROUPS=
+ CUEWEB_ALLOWED_GROUPS=
+ CUEWEB_AUTHZ_ENABLED=false
 CUEWEB_GROUPS_CLAIM=groups
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cueweb/.env.example` around lines 15 - 27, The authorization environment
variables in the .env.example file are not in alphabetical order, which causes
dotenv-linter to flag the configuration. Reorder the four authorization-related
variables (CUEWEB_ADMIN_GROUPS, CUEWEB_ALLOWED_GROUPS, CUEWEB_AUTHZ_ENABLED, and
CUEWEB_GROUPS_CLAIM) so they appear in strict alphabetical order while keeping
their associated comments aligned with each variable definition.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cueweb/lib/auth.ts`:
- Around line 173-181: The jwt callback in the jwt function only assigns
token.groups when the extractGroups result has length greater than 0, causing
stale group claims to persist if groups become empty after initial sign-in.
Instead of conditionally assigning token.groups only when groups.length > 0,
always assign token.groups = groups after calling extractGroups, even if the
result is an empty array, to ensure that cleared group membership is reflected
on the token and prevent over-authorization from stale group claims.

In `@cueweb/lib/authz.ts`:
- Around line 96-98: The normalization of array-based group values in the block
where Array.isArray(raw) is checked does not trim whitespace from stringified
values, causing entries like "admins " to fail matching against configured
groups. Modify the map function that converts group values using String(g) to
also apply trim() immediately after stringification, ensuring leading and
trailing whitespace is removed before the filter(Boolean) call validates the
results.

---

Nitpick comments:
In `@cueweb/.env.example`:
- Around line 15-27: The authorization environment variables in the .env.example
file are not in alphabetical order, which causes dotenv-linter to flag the
configuration. Reorder the four authorization-related variables
(CUEWEB_ADMIN_GROUPS, CUEWEB_ALLOWED_GROUPS, CUEWEB_AUTHZ_ENABLED, and
CUEWEB_GROUPS_CLAIM) so they appear in strict alphabetical order while keeping
their associated comments aligned with each variable definition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 394c0912-7d08-4318-8ee9-668b226e0530

📥 Commits

Reviewing files that changed from the base of the PR and between ca5f70f and 5275cbe.

📒 Files selected for processing (10)
  • cueweb/.env.example
  • cueweb/README.md
  • cueweb/app/unauthorized/page.tsx
  • cueweb/lib/auth.ts
  • cueweb/lib/authz.ts
  • cueweb/middleware.ts
  • docs/_docs/developer-guide/cueweb-development.md
  • docs/_docs/getting-started/deploying-cueweb.md
  • docs/_docs/reference/cueweb.md
  • docs/_docs/user-guides/cueweb-user-guide.md

Comment thread cueweb/lib/auth.ts Outdated
Comment thread cueweb/lib/authz.ts
- auth.ts: always set token.groups at sign-in (even to []), so a user whose group membership was cleared no longer carries stale memberships
- authz.ts: trim array-based group claim values during normalization so entries like "admins " still match configured groups
@ramonfigueiredo

Copy link
Copy Markdown
Collaborator Author

@DiegoTavares / @lithorus
Ready for review!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant