Skip to content

Add scoped permissions for API keys#148

Open
sjmiller609 wants to merge 5 commits intomainfrom
hypeship/scoped-api-key-permissions
Open

Add scoped permissions for API keys#148
sjmiller609 wants to merge 5 commits intomainfrom
hypeship/scoped-api-key-permissions

Conversation

@sjmiller609
Copy link
Collaborator

@sjmiller609 sjmiller609 commented Mar 17, 2026

Summary

  • Adds a lib/scopes package that defines permission scopes following the resource:action pattern (e.g., instance:read, image:write, build:delete)
  • JWT tokens can now carry a permissions claim with an array of scope strings; tokens without this claim retain full access (backward compatible)
  • Auth middleware (JwtAuth and OapiAuthenticationFunc) extracts the permissions claim and stores parsed scopes in the request context
  • A new scope enforcement middleware rejects requests missing the required scope with 403 Forbidden
  • The hypeman-token CLI gains -scopes (comma-separated scope list) and -list-scopes flags
  • WebSocket endpoints (exec, cp) enforce instance:write scope via RequireScope

Scope mapping

All API routes are mapped to scopes in lib/scopes/scopes.go:routeScopes. The resource types are:

Scope prefix Resources
instance: instances, exec, cp, start/stop/standby/restore/fork
image: images
volume: volumes, attach/detach
snapshot: snapshots, instance snapshots
build: builds
device: devices
ingress: ingresses
resource: health, resources

Each prefix supports read, write, and delete actions (except resource: which is read-only). The wildcard * grants all permissions.

Usage

# Full-access token (backward compatible, no permissions claim)
hypeman-token -user-id myuser -duration 8760h

# Read-only token for instances and images
hypeman-token -user-id myuser -scopes "instance:read,image:read"

# Token that can manage instances but not delete them
hypeman-token -user-id myuser -scopes "instance:read,instance:write"

# List available scopes
hypeman-token -list-scopes

Test plan

  • go test ./lib/scopes/ — scope parsing, validation, context helpers, RequireScope middleware
  • go test ./lib/middleware/ — legacy tokens get full access, scoped tokens have permissions in context, wildcard tokens work
  • go vet clean on all changed packages
  • Integration test with live API: create a scoped token, verify allowed endpoints succeed and denied endpoints return 403

🤖 Generated with Claude Code


Note

Medium Risk
Introduces new authorization checks across API routes based on JWT permissions claims; misconfigured scope mappings or claim parsing could unintentionally block access or over/under-authorize requests.

Overview
Adds scoped API-key permissions via a new lib/scopes package, including scope definitions (e.g. instance:read), a per-route scope map, and middleware that returns 403 Forbidden when a request lacks the required scope.

Updates JWT authentication (JwtAuth and OapiAuthenticationFunc) to extract an optional permissions claim into request context (missing claim remains full access for backward compatibility; malformed claim becomes deny all), wires scope enforcement into the main API router, and applies instance:write checks to the exec/cp WebSocket endpoints.

Extends the hypeman-token CLI to list available scopes and mint scoped tokens, and adds tests to ensure scope enforcement works and that all routes are mapped (or explicitly public).

Written by Cursor Bugbot for commit 1f3e39e. This will update automatically on new commits. Configure here.

Implement a permissions system for API keys so tokens can be restricted
to specific operations instead of having full access. Scopes follow the
pattern "resource:action" (e.g., instance:read, image:write, build:delete).

Key changes:
- New lib/scopes package with scope constants, context helpers, and middleware
- JWT tokens can now carry a "permissions" claim with an array of scope strings
- Auth middleware extracts permissions from JWT and stores in request context
- Scope middleware enforces per-route permission requirements
- Token CLI (hypeman-token) supports -scopes flag and -list-scopes
- Backward compatible: tokens without "permissions" claim get full access
- Uses "permissions" claim name to avoid collision with registry token "scope"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sjmiller609 and others added 2 commits March 17, 2026 14:29
Documents the feature from a user/operator perspective: available scopes
by resource type, CLI usage for creating scoped tokens, backward
compatibility, and example scenarios for common use cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sjmiller609 sjmiller609 marked this pull request as ready for review March 17, 2026 15:20
Adds three tests in lib/scopes/routes_test.go:
- TestAllRoutesHaveScopes: builds the full chi router (OpenAPI + manual
  routes) and asserts every route has a scope in RouteScopes or is
  explicitly marked in PublicRoutes. Fails CI if a new endpoint is added
  without a scope mapping.
- TestRouteScopesHaveNoStaleEntries: catches stale scope entries left
  behind when endpoints are removed.
- TestPublicRoutesAreNotInRouteScopes: ensures no route is
  contradictorily listed in both maps.

Also exports RouteScopes and adds PublicRoutes for spec.yaml, spec.json,
and swagger endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

… tests

- extractPermissions now stores an empty permission set (deny all) when
  the "permissions" claim is present but not a valid array, preventing
  privilege escalation from malformed tokens.
- Add middleware integration test (TestMiddleware_EnforcesScopes) that
  proves scope enforcement works end-to-end with a real chi router:
  blocks missing scopes, allows matching scopes, wildcard, legacy
  tokens, and empty permissions.
- Add test for malformed permissions claim in JwtAuth middleware.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sjmiller609 sjmiller609 requested review from hiroTamada, masnwilliams and rgarcia and removed request for hiroTamada and rgarcia March 17, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant