Roles and Permissions
Ephor uses role-based access control (RBAC). Roles are assigned based on group memberships from the identity provider.
Role Mapping
When a user authenticates, oauth2-proxy forwards their groups in the X-Forwarded-Groups header. Ephor maps these to internal roles:
| Group | Role |
|---|---|
ephor-viewers | Viewer |
ephor-analysts | Analyst |
ephor-leads | Lead |
ephor-admins | Admin |
If a user belongs to multiple groups, their effective role is the highest-privilege match.
Permissions by Role
Viewer
Read-only access to security data.
| Permission | Description |
|---|---|
VIEW_VULNERABILITIES | View vulnerability findings and details |
VIEW_ESCALATIONS | View escalations |
VIEW_TRIAGE | View triage status and history |
VIEW_REMEDIATIONS | View remediation records |
Analyst
All Viewer permissions plus:
| Permission | Description |
|---|---|
MANAGE_VULNERABILITIES | Update vulnerability status and metadata |
MANAGE_ESCALATIONS | Create and update escalations |
MANAGE_TRIAGE | Update triage status and add comments |
MANAGE_REMEDIATIONS | Create and update remediation records |
Lead
All Analyst permissions plus:
| Permission | Description |
|---|---|
VIEW_ADMIN | Access admin-level views and reports |
Admin
All permissions including:
| Permission | Description |
|---|---|
MANAGE_ADMIN | Manage system configuration and all administrative functions |
Group Extraction by Provider
Keycloak -- Groups are extracted from the groups claim in the JWT token. The default development configuration includes this claim automatically.
GitHub -- Groups are resolved by looking up the user's team memberships in the configured organization. The GITHUB_TOKEN must have read:org scope. The organization prefix is stripped automatically (e.g., holbein-io:ephor-analysts becomes ephor-analysts).
Custom providers -- The X-Forwarded-Groups header must contain a comma-separated list of group names matching the mappings above.
API Authorization
For developers extending the API, the @RequireAuth annotation enforces access control:
// Any authenticated user
@RequireAuth
@GetMapping("/resource")
public ResponseEntity<?> get() { ... }
// Specific permission required
@RequireAuth(permissions = {Permission.MANAGE_VULNERABILITIES})
@PutMapping("/vulnerabilities/{id}")
public ResponseEntity<?> update() { ... }
// Specific groups required
@RequireAuth(groups = {"ephor-admins"})
@DeleteMapping("/resource/{id}")
public ResponseEntity<?> delete() { ... }
// Multiple groups (all required)
@RequireAuth(groups = {"ephor-admins", "ephor-leads"}, requireAllGroups = true)
@PostMapping("/admin/action")
public ResponseEntity<?> adminAction() { ... }