Jump to heading Authorization System
Scotty includes a powerful scope-based authorization system that controls access to applications and their features. This system allows you to restrict sensitive operations, isolate applications by team or environment, and support multi-tenant scenarios.
Jump to heading Overview
The authorization system is built on Casbin RBAC and provides:
- Scope-based access control: Organize apps into logical scopes
- Role-based permissions: Define what actions users can perform
- Flexible assignments: Assign users to roles within specific scopes
- Bearer token integration: Secure API access with granular permissions
- Automatic synchronization: Apps declare scope membership via configuration
Jump to heading Core Concepts
Jump to heading App Scopes
Collections of applications organized by purpose:
- Environment-based:
production,staging,development - Team-based:
team-frontend,team-backend,platform - Client-based:
client-acme,client-widgets - Purpose-based:
databases,services,tools
Apps can belong to multiple scopes simultaneously (e.g., an app could be in both production and team-frontend scopes).
Jump to heading Permissions
Granular actions users can perform on applications and the system:
App-Specific Permissions (require app context):
view- See app status and informationmanage- Start, stop, restart applicationslogs- View application logsshell- Execute shell commands in containerscreate- Create new apps in scopedestroy- Delete apps from scope
Global Permissions (not tied to specific apps):
admin_read- Read authorization configuration (scopes, roles, assignments, permissions)admin_write- Modify authorization configuration (create/update scopes, roles, assignments)
Jump to heading Roles
Named collections of permissions for common access patterns:
admin- All permissions (wildcard*)developer- Full access except destroy:[view, manage, shell, logs, create]operator- Operations without shell:[view, manage, logs]viewer- Read-only access:[view]system_admin- Authorization management:[admin_read, admin_write]
Jump to heading Assignments
Map users or bearer tokens to roles within specific scopes:
assignments:
"frontend-dev@example.com":
- role: "developer"
scopes: ["frontend", "staging"]
"bearer:dev-token":
- role: "developer"
scopes: ["development"]
Jump to heading Configuration
Jump to heading Authorization Setup
Create /config/casbin/policy.yaml:
# Scope definitions
scopes:
frontend:
description: "Frontend applications"
created_at: "2023-12-01T00:00:00Z"
backend:
description: "Backend services"
created_at: "2023-12-01T00:00:00Z"
production:
description: "Production environment"
created_at: "2023-12-01T00:00:00Z"
# Role definitions
roles:
admin:
description: "Full administrative access"
permissions: ["*"]
developer:
description: "Full development access"
permissions: ["view", "manage", "shell", "logs", "create"]
operator:
description: "Operations access without shell"
permissions: ["view", "manage", "logs"]
system_admin:
description: "System administration access"
permissions: ["admin_read", "admin_write"]
# User assignments
assignments:
"frontend-dev@example.com":
- role: "developer"
scopes: ["frontend"]
"backend-dev@example.com":
- role: "developer"
scopes: ["backend"]
"ops@example.com":
- role: "operator"
scopes: ["frontend", "backend", "production"]
"admin@example.com":
- role: "admin"
scopes: ["*"] # Global access
"system-admin@example.com":
- role: "system_admin"
scopes: ["*"] # Can manage authorization but not apps
# App scope mappings (managed automatically)
apps:
"my-frontend-app": ["frontend"]
"my-backend-api": ["backend"]
"shared-service": ["frontend", "backend"]
Jump to heading App Scope Assignment
Apps declare scope membership in their .scotty.yml file:
# App belongs to frontend and staging scopes
scopes:
- "frontend"
- "staging"
public_services:
- service: "web"
port: 3000
domains: []
environment:
NODE_ENV: "development"
Apps without explicit scopes are assigned to the default scope.
Jump to heading Authentication Integration
Jump to heading Bearer Token Authentication
The authorization system requires explicit bearer token assignments:
- RBAC Only: Only tokens explicitly assigned in authorization configuration are accepted
- No Legacy Fallback: The
api.access_tokenconfiguration is no longer used - Token Format: Bearer tokens are identified as
bearer:<token>in assignments
# Using a bearer token with authorization (token must be in assignments)
curl -H "Authorization: Bearer admin" \
https://scotty.example.com/api/v1/authenticated/apps/list
Important: Bearer tokens that are not explicitly listed in the assignments section will be rejected with a 401 Unauthorized response.
Jump to heading OAuth Integration
OAuth users are identified by their email address and can be assigned to roles:
assignments:
"alice@company.com":
- role: "admin"
scopes: ["*"]
"bob@company.com":
- role: "developer"
scopes: ["team-frontend"]
Jump to heading Permission Enforcement
Jump to heading API Endpoints
All API endpoints are protected by permission checks:
App Management Endpoints:
- App List:
/api/v1/authenticated/apps/list- Requiresviewpermission, shows only accessible apps - App Management: Start/stop/restart operations - Requires
managepermission - App Creation:
/api/v1/authenticated/apps(POST) - Requirescreatepermission - Shell Access: WebSocket shell sessions - Requires
shellpermission - App Destruction: Delete operations - Requires
destroypermission
Admin API Endpoints (require global permissions):
- Scopes:
/api/v1/authenticated/admin/scopes- GET - Requires
admin_read- List all scopes - POST - Requires
admin_write- Create new scope
- GET - Requires
- Roles:
/api/v1/authenticated/admin/roles- GET - Requires
admin_read- List all roles - POST - Requires
admin_write- Create new role
- GET - Requires
- Assignments:
/api/v1/authenticated/admin/assignments- GET - Requires
admin_read- List all assignments - POST - Requires
admin_write- Create new assignment - DELETE - Requires
admin_write- Remove assignment
- GET - Requires
- Permissions:
/api/v1/authenticated/admin/permissions- GET - Requires
admin_read- List available permissions - POST
/test- Requiresadmin_read- Test permission for user/app combination
- GET - Requires
- User Permissions:
/api/v1/authenticated/admin/users/:user_id/permissions- GET - Requires
admin_read- Get permissions for specific user
- GET - Requires
Jump to heading Denied Access
When access is denied, users receive:
- HTTP 403 Forbidden responses
- Clear error messages explaining required permissions
- Empty results for list operations (apps they cannot access are hidden)
Jump to heading Examples
Jump to heading Multi-Team Setup
# Teams with separate environments
scopes:
team-alpha:
description: "Team Alpha applications"
team-beta:
description: "Team Beta applications"
production:
description: "Production environment"
assignments:
# Team Alpha developer
"alice@company.com":
- role: "developer"
scopes: ["team-alpha"]
- role: "viewer"
scopes: ["production"]
# Team Beta developer
"bob@company.com":
- role: "developer"
scopes: ["team-beta"]
- role: "viewer"
scopes: ["production"]
# Platform engineer
"charlie@company.com":
- role: "operator"
scopes: ["production"]
- role: "admin"
scopes: ["team-alpha", "team-beta"]
Jump to heading System Administration Example
Separate authorization management from app management:
assignments:
# System administrator - can manage authorization but NOT apps
"auth-admin@example.com":
- role: "system_admin"
scopes: ["*"]
# App administrator - can manage apps but NOT authorization
"app-admin@example.com":
- role: "admin"
scopes: ["production", "staging"]
This separation allows you to:
- Grant authorization management (creating users/roles) without app access
- Grant app management without ability to change authorization
- Implement least privilege principle for admin roles
Jump to heading Bearer Token Access
Configure bearer tokens in authorization assignments using their logical identifiers:
assignments:
# CI/CD deployment token (maps to bearer_tokens.deployment in API config)
"identifier:deployment":
- role: "developer"
scopes: ["staging"]
# Monitoring token (maps to bearer_tokens.monitoring in API config)
"identifier:monitoring":
- role: "viewer"
scopes: ["production", "staging"]
# Admin token (maps to bearer_tokens.admin in API config)
"identifier:admin":
- role: "admin"
scopes: ["*"]
Security Reminder: The actual bearer tokens should be configured via environment variables:
# Set secure tokens via environment variables
export SCOTTY__API__BEARER_TOKENS__DEPLOYMENT="$(openssl rand -base64 32)"
export SCOTTY__API__BEARER_TOKENS__MONITORING="$(openssl rand -base64 32)"
export SCOTTY__API__BEARER_TOKENS__ADMIN="$(openssl rand -base64 32)"
Jump to heading Best Practices
Jump to heading Security
- Principle of Least Privilege: Grant minimum required permissions
- Scope Isolation: Use scopes to separate sensitive environments
- Regular Audits: Review assignments and remove unused access
- Emergency Access: Maintain admin access for critical situations
Jump to heading Organization
- Clear Naming: Use descriptive scope and role names
- Documentation: Document scope purposes and access patterns
- Consistency: Establish naming conventions for scopes
- Automation: Integrate with CI/CD for app scope assignment
Jump to heading Performance
- Scope Structure: Keep scope hierarchies simple
- Assignment Scope: Avoid overly broad assignments
- Caching: Authorization checks are cached for performance
- Regular Cleanup: Remove obsolete scopes and assignments
Jump to heading Migration
Jump to heading Existing Installations
For existing Scotty installations:
- Breaking Change: Bearer token authentication now requires RBAC assignments
- Migration Required: Existing
api.access_tokenmust be added to assignments - App Discovery: Existing apps are assigned to
defaultscope automatically - OAuth Compatibility: OAuth authentication continues to work unchanged
Jump to heading Enabling Authorization
- Create
/config/casbin/model.confand/config/casbin/policy.yaml - Define initial scopes, roles, and assignments
- Add existing bearer tokens to assignments (if using bearer authentication)
- Apps will automatically sync their scope memberships
- API endpoints begin enforcing permissions immediately
Migration Example: If you currently use api.access_token: "my-secret-token", follow these steps:
- Update API configuration to use
api.bearer_tokenswith a logical identifier:
api:
bearer_tokens:
legacy: "OVERRIDE_VIA_ENV_VAR" # Will be overridden by environment variable
- Set the actual token via environment variable:
export SCOTTY__API__BEARER_TOKENS__LEGACY="my-secret-token"
- Add the identifier to authorization policy.yaml:
assignments:
"identifier:legacy":
- role: "admin"
scopes: ["*"]
Recommended: Generate a new secure token instead of reusing the old one:
export SCOTTY__API__BEARER_TOKENS__ADMIN="$(openssl rand -base64 32)"
Warning: The authorization system no longer falls back to legacy configuration. Missing token assignments will result in authentication failures.