The Stellar Micro-Donation API implements a Role-Based Access Control (RBAC) system to manage user permissions and secure API endpoints.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β API Request β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β attachUserRole Middleware β
β (Extracts user role from API key/JWT) β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β checkPermission Middleware β
β (Validates user has required permission) β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
ββββββ΄βββββ
β β
Allowed Denied
β β
βΌ βΌ
Route Handler 403 Forbidden
- Description: Full system access
- Permissions: All permissions (wildcard
*) - Use Case: System administrators, super users
- Description: Regular authenticated user
- Permissions:
donations:create- Create donationsdonations:read- View donationsdonations:verify- Verify transactionswallets:create- Create wallet metadatawallets:read- View wallet informationwallets:update- Update wallet metadatastream:create- Create recurring donation schedulesstream:read- View recurring schedulesstream:update- Update schedulesstream:delete- Cancel schedulesstats:read- View statistics
- Description: Unauthenticated or read-only access
- Permissions:
donations:read- View donationsstats:read- View statistics
Permissions follow the format: resource:action
Examples:
donations:createwallets:readstream:delete*(wildcard - all permissions)donations:*(all donation permissions)
Checks if the user has a specific permission.
const { checkPermission } = require('./middleware/rbacMiddleware');
const { PERMISSIONS } = require('./utils/permissions');
router.post('/donations',
checkPermission(PERMISSIONS.DONATIONS_CREATE),
donationController.create
);Checks if the user has ANY of the specified permissions.
router.get('/data',
checkAnyPermission([
PERMISSIONS.DONATIONS_READ,
PERMISSIONS.STATS_READ
]),
dataController.get
);Checks if the user has ALL of the specified permissions.
router.post('/admin/action',
checkAllPermissions([
PERMISSIONS.DONATIONS_CREATE,
PERMISSIONS.WALLETS_CREATE
]),
adminController.action
);Checks if the user has admin role.
router.delete('/admin/purge',
requireAdmin(),
adminController.purge
);Attaches user role to the request object based on authentication.
app.use(attachUserRole());const express = require('express');
const router = express.Router();
const { checkPermission } = require('../middleware/rbacMiddleware');
const { PERMISSIONS } = require('../utils/permissions');
// Only authenticated users can create donations
router.post('/',
checkPermission(PERMISSIONS.DONATIONS_CREATE),
async (req, res) => {
// Handle donation creation
}
);
// Anyone can read donations (including guests)
router.get('/',
checkPermission(PERMISSIONS.DONATIONS_READ),
async (req, res) => {
// Handle donation listing
}
);// User needs either permission
router.get('/reports',
checkAnyPermission([
PERMISSIONS.STATS_READ,
PERMISSIONS.STATS_ADMIN
]),
reportController.get
);
// User needs both permissions
router.post('/bulk-action',
checkAllPermissions([
PERMISSIONS.DONATIONS_CREATE,
PERMISSIONS.WALLETS_CREATE
]),
bulkController.action
);Currently, the system uses API keys for authentication (development mode):
- Admin Key:
admin-key-123β Admin role - Any other key: β User role
- No key: β Guest role
# As admin
curl -H "x-api-key: admin-key-123" http://localhost:3000/donations
# As user
curl -H "x-api-key: user-key-456" http://localhost:3000/donations
# As guest (no key)
curl http://localhost:3000/donationsFor production deployment, replace the mock attachUserRole middleware with proper authentication:
- JWT Authentication:
const jwt = require('jsonwebtoken');
exports.attachUserRole = () => {
return (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
req.user = { role: 'guest' };
return next();
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = {
id: decoded.userId,
role: decoded.role,
name: decoded.name
};
next();
} catch (error) {
req.user = { role: 'guest' };
next();
}
};
};- Session-Based Authentication:
exports.attachUserRole = () => {
return (req, res, next) => {
if (req.session && req.session.user) {
req.user = req.session.user;
} else {
req.user = { role: 'guest' };
}
next();
};
};Returned when authentication is required but not provided.
{
"success": false,
"error": "Authentication required"
}Returned when user is authenticated but lacks required permissions.
{
"success": false,
"error": "Insufficient permissions. Required: donations:create"
}- Update roles.json:
{
"roles": [
{
"name": "user",
"permissions": [
"existing:permission",
"new:permission"
]
}
]
}- Add constant to permissions.js:
const PERMISSIONS = {
// ... existing
NEW_PERMISSION: 'new:permission'
};- Apply to routes:
router.post('/new-endpoint',
checkPermission(PERMISSIONS.NEW_PERMISSION),
controller.action
);Run the permission tests:
npm test tests/permissions.test.js
npm test tests/rbac-middleware.test.js- Always authenticate sensitive endpoints
- Use least privilege principle - Grant minimum required permissions
- Validate permissions on every request - Don't cache permission checks
- Log permission denials - Monitor for potential security issues
- Use HTTPS in production - Protect API keys and tokens in transit
- Rotate API keys regularly - Implement key rotation policy
- Implement rate limiting - Prevent brute force attacks
- Audit permission changes - Log all role and permission modifications
- Check user role:
console.log(req.user.role) - Verify permission exists in roles.json
- Ensure middleware is applied in correct order
- Check for typos in permission strings
- Verify API key is being sent in headers
- Check
attachUserRolemiddleware is applied - Ensure middleware runs before permission checks
- Database-backed roles and permissions
- Dynamic permission assignment
- Permission inheritance
- Resource-level permissions (e.g., "can edit own donations")
- Time-based permissions
- IP-based access control
- Two-factor authentication
- OAuth2 integration