Permission Service Integration
Overview
The PermissionService is a centralized authorization service that:- Queries user roles from Better Auth PostgreSQL tables
- Maps roles to permissions (e.g.,
owner→["org:manage", "data:write", "leave:approve", ...]) - Caches permission lookups for 5 minutes
- Provides methods to check authorization in your use cases
Interface
The PermissionService implements theport.PermissionService interface:
Usage Patterns
Pattern 1: Check Specific Permission
When: You need to verify a single permission like “data:write” or “leave:approve”Pattern 2: Check Role
When: You need to know what role the user has (for role-specific logic or UI rendering)Pattern 3: Check Multiple Permissions (Any)
When: User needs ANY of several permissions to proceedPattern 4: Leave Approval (Pre-Built Method)
When: Checking if user can approve leave for an employeeIntegration with Dependency Injection
In Module Initialization
In Your Use Case
Caching Behavior
Cache Details
- Key:
perm:<userId>:<organizationId> - TTL: 5 minutes
- Stored: User’s org role + resolved permissions array
How It Works
First request:Performance Impact
- Cached: ~1-2 µs (map lookup)
- Uncached: ~10-50 ms (DB query + resolution)
Error Handling
Common Errors
Defensive Coding
Always treat missing users as “not authorized”:Permission Reference
Available Permissions
| Permission | Role | Meaning |
|---|---|---|
data:read | staff, member, viewer | Read data/records |
data:write | owner, admin, staff | Write/edit data |
leave:request | owner, admin, staff, member | Request leave |
leave:approve | owner, admin | Approve leave requests |
member:invite | owner, admin | Invite members |
member:manage | owner, admin | Update member roles |
member:remove | owner, admin | Remove members |
org:manage | owner, admin | Manage org settings |
report:view | owner, admin | View reports |
report:export | owner, admin | Export reports |
Role-to-Permission Mapping
Middleware Integration
Auto-Extracting Organization from JWT
The request context containsorganization_id from the JWT. Use it:
Testing
Unit Test Example
FAQ
Q: Can I change permission mappings?
A: The mappings are hardcoded inpermission_service.go (the defaultRolePermissions map). To change them, edit this file and redeploy. This is intentional — permissions are part of system design, not runtime configuration.
Q: What if I need real-time permission updates (< 5 sec)?
A: Options:- Use shorter TTL: Change cache TTL from 5 min to 1 min in
NewPermissionService() - Subscribe to events: Have Bun publish a NATS event when role changes, Go listens and invalidates cache
- Disable cache: Return false from cache.get() to force DB queries (not recommended for performance)
Q: Can I add new permissions?
A: Yes:- Add the permission string to the appropriate role in
defaultRolePermissions - Use it in your service:
HasPermission(ctx, user, org, "my:new:permission") - Test it
Q: What about superadmins?
A: Platform superadmins (fromauth.role = "superadmin") can do anything. Check with IsUserSuperAdmin(ctx, userID) if needed.
Related Documentation
- Role Assignment and Authorization — How roles are assigned via Better Auth
- Authentication Architecture — JWT validation and Better Auth integration
- Leave Module Integration — Real-world usage example