Permissions Guide
DeePsy uses a bitfield-based permission system that provides granular control over API access. Each user can have different permission levels for different companies, and API keys inherit these permissions with additional company-specific authorization.
Permission Levels
The DeePsy API uses six distinct permission levels, each with a specific bitfield value:
Permission | Value | Description |
---|---|---|
FOUNDER | 1 | Full access to everything, including company deletion and ownership transfer |
ADMINISTRATOR | 2 | Company administration rights, user management, and most operations |
MANAGE_CAMPAIGN | 4 | Campaign creation, management, and candidate operations |
FINANCE | 8 | Financial operations, billing, and subscription management |
REPORT | 16 | Report generation, data export, and analytics access |
EMAIL | 32 | Email management, sending notifications, and communication features |
Permission Hierarchy
Permissions are not hierarchical. Each permission grants access to specific functionality:
- FOUNDER has all permissions by default
- ADMINISTRATOR can manage users and company settings but needs additional permissions for campaigns, finance, reports, or emails
- Other permissions are specific to their functional areas
Bitfield Operations
Understanding Bitfield Values
Permissions are stored as integers using bitwise operations. Multiple permissions are combined using bitwise OR:
ADMINISTRATOR + MANAGE_CAMPAIGN = 2 + 4 = 6
ADMINISTRATOR + MANAGE_CAMPAIGN + REPORT = 2 + 4 + 16 = 22
Interactive Permissions Calculator
Use this interactive tool to calculate permission bitfield values. Click on the permission tags to toggle them on/off and see the resulting bitfield value.
Click on the permission tags above to toggle them on or off.
Note: FOUNDER (1) gives all permissions. ADMINISTRATOR (2) gives all permissions except FOUNDER.
Checking Permissions
Here's the actual permission checking code used in the DeePsy application:
- JavaScript
- TypeScript
// Permission constants from DeePsy codebase
export const permissions = {
1: 'FOUNDER',
2: 'ADMINISTRATOR',
4: 'MANAGE_CAMPAIGN',
8: 'FINANCE',
16: 'REPORT',
32: 'EMAIL',
};
// Calculate permissions from bitfield
export const calculatePermissions = (bitfield) => {
const userPermissions = [];
// FOUNDER has all permissions
if (bitfield & 1) return Object.values(permissions);
// ADMINISTRATOR has all permissions except FOUNDER
if (bitfield & 2) {
const adminPermissions = Object.values(permissions).filter(perm => perm !== 'FOUNDER');
return adminPermissions;
}
// Check each permission bit
for (const bit in permissions) {
if (bitfield & bit) {
userPermissions.push(permissions[bit]);
}
}
return userPermissions;
};
// Example usage:
const userBitfield = 6; // ADMINISTRATOR + MANAGE_CAMPAIGN
const userPermissions = calculatePermissions(userBitfield);
// Returns: ['ADMINISTRATOR', 'MANAGE_CAMPAIGN', 'FINANCE', 'REPORT', 'EMAIL']
// Check if user has specific permission
const hasManageCampaign = userPermissions.includes('MANAGE_CAMPAIGN'); // true
const hasFounder = userPermissions.includes('FOUNDER'); // false
// Permission types and constants from DeePsy codebase
type PermissionKey = 1 | 2 | 4 | 8 | 16 | 32;
type PermissionName = 'FOUNDER' | 'ADMINISTRATOR' | 'MANAGE_CAMPAIGN' | 'FINANCE' | 'REPORT' | 'EMAIL';
export const permissions: Record<PermissionKey, PermissionName> = {
1: 'FOUNDER',
2: 'ADMINISTRATOR',
4: 'MANAGE_CAMPAIGN',
8: 'FINANCE',
16: 'REPORT',
32: 'EMAIL',
};
// Calculate permissions from bitfield
export const calculatePermissions = (bitfield: number): PermissionName[] => {
const userPermissions: PermissionName[] = [];
// FOUNDER has all permissions
if (bitfield & 1) return Object.values(permissions);
// ADMINISTRATOR has all permissions except FOUNDER
if (bitfield & 2) {
const adminPermissions = Object.values(permissions).filter(perm => perm !== 'FOUNDER');
return adminPermissions;
}
// Check each permission bit
for (const bit in permissions) {
const numericBit = Number(bit) as PermissionKey;
if (bitfield & numericBit) {
userPermissions.push(permissions[numericBit]);
}
}
return userPermissions;
};
// Example usage:
const userBitfield = 6; // ADMINISTRATOR + MANAGE_CAMPAIGN
const userPermissions = calculatePermissions(userBitfield);
// Returns: ['ADMINISTRATOR', 'MANAGE_CAMPAIGN', 'FINANCE', 'REPORT', 'EMAIL']
// Check if user has specific permission
const hasManageCampaign: boolean = userPermissions.includes('MANAGE_CAMPAIGN'); // true
const hasFounder: boolean = userPermissions.includes('FOUNDER'); // false
React Permission Checking Hook
This is an actual example that's used in the DeePsy dashboard to mainly check if the user has the required permissions to access a specific route:
- JavaScript
- TypeScript
// Permission checking hook from DeePsy codebase
export const useCheckUserPermissions = (requiredPermissions) => {
const selectedCompany = useSelectedCompanyStore((state) => state.selectedCompany);
const companies = useUserStore((state) => state.companies);
return useMemo(() => {
if (!selectedCompany || !selectedCompany.company_id || !requiredPermissions || !requiredPermissions.length) {
return { hasPermissions: true, userPermissions: [] };
}
const userCompany = companies.find(company => company.company_id === selectedCompany.company_id);
if (!userCompany || !userCompany.permissions) {
return { hasPermissions: false, userPermissions: [] };
}
const userPermissions = calculatePermissions(userCompany.permissions);
const hasAllPermissions = requiredPermissions.every(permission =>
userPermissions.includes(permission)
);
return {
hasPermissions: hasAllPermissions,
userPermissions
};
}, [selectedCompany, companies, requiredPermissions]);
};
// Example usage in React component:
const MyComponent = () => {
const { hasPermissions, userPermissions } = useCheckUserPermissions(['MANAGE_CAMPAIGN', 'REPORT']);
if (!hasPermissions) {
return <div>You don't have permission to view this content</div>;
}
return <div>Campaign management interface</div>;
};
import { useMemo } from 'react';
import { PermissionName } from '../types/permissions';
interface Company {
company_id: string;
permissions: number;
// other company properties
}
interface SelectedCompany {
company_id: string;
// other selected company properties
}
// Permission checking hook from DeePsy codebase
export const useCheckUserPermissions = (requiredPermissions: PermissionName[]) => {
const selectedCompany = useSelectedCompanyStore((state) => state.selectedCompany as SelectedCompany);
const companies = useUserStore((state) => state.companies as Company[]);
return useMemo(() => {
if (!selectedCompany || !selectedCompany.company_id || !requiredPermissions || !requiredPermissions.length) {
return { hasPermissions: true, userPermissions: [] as PermissionName[] };
}
const userCompany = companies.find(company => company.company_id === selectedCompany.company_id);
if (!userCompany || !userCompany.permissions) {
return { hasPermissions: false, userPermissions: [] as PermissionName[] };
}
const userPermissions = calculatePermissions(userCompany.permissions);
const hasAllPermissions = requiredPermissions.every(permission =>
userPermissions.includes(permission)
);
return {
hasPermissions: hasAllPermissions,
userPermissions
};
}, [selectedCompany, companies, requiredPermissions]);
};
// Example usage in React component:
const MyComponent: React.FC = () => {
const { hasPermissions, userPermissions } = useCheckUserPermissions(['MANAGE_CAMPAIGN', 'REPORT']);
if (!hasPermissions) {
return <div>You don't have permission to view this content</div>;
}
return <div>Campaign management interface</div>;
};
Common Permission Combinations
Value | Permissions |
---|---|
1 | All permissions including FOUNDER |
2 | All permissions except FOUNDER |
60 | All permissions except FOUNDER and ADMINISTRATOR |
4 | MANAGE_CAMPAIGN |
8 | FINANCE |
16 | REPORT |
32 |
API Key Permissions
Two-Level Authorization
API keys require two levels of authorization:
- API Key Permissions: API keys have permissions independent from the user's permissions
- API Key Authorization: Company administrators must authorize your API key and grant specific permissions
API Key Creation Process
- Create API Key: Generate an API key in your developer settings
- Select Companies: Choose which companies the key should access
- Admin Authorization: Company administrators authorize the key and select permissions
- API Access: Use the authorized key to access company resources
Permission Inheritance
API keys do not automatically inherit all user permissions. Company administrators can grant a subset of permissions to API keys for security purposes.
Endpoint Permission Requirements
User Management
- GET /user/me: Any valid API key
- GET /user/companies: Any valid API key
Company Management
- GET /companies/{id}/get-details: Company membership (any permission)
- GET /companies/{id}/users: ADMINISTRATOR or FOUNDER
- POST /companies/{id}/invitations/create: ADMINISTRATOR or FOUNDER
Campaign Management
- GET /campaign/{id}/list: MANAGE_CAMPAIGN or higher
- POST /campaign/{id}/create: MANAGE_CAMPAIGN or higher
- PUT /campaign/{id}/{campaign_id}/update: MANAGE_CAMPAIGN or higher
Candidate Management
- GET /candidates/{id}/{campaign_id}/list: MANAGE_CAMPAIGN or REPORT
- POST /candidates/{id}/{campaign_id}/{candidate_id}/unlock-test: MANAGE_CAMPAIGN
- POST /candidates/{id}/{campaign_id}/{candidate_id}/followup-email: EMAIL
White Label Management
- GET /whitelabels/{id}/list: ADMINISTRATOR or FOUNDER
- POST /whitelabels/{id}/create: ADMINISTRATOR or FOUNDER
- PUT /whitelabels/{id}/{logo_id}/update: ADMINISTRATOR or FOUNDER
Reports and Analytics
- GET /candidates/{id}/{campaign_id}/{candidate_id}/get-attempt-details: REPORT
- POST /candidates/{id}/{campaign_id}/{candidate_id}/{attempt_ref}/generate-pdf: REPORT
Permission Checking in API Responses
User Profile Response
In /user/me
, permissions are returned as bitfield integers:
{
"companies": [
{
"company_id": "c193a06f-1c25-4e65-84a7-95faaae7ae7b",
"permissions": 6, // ADMINISTRATOR + MANAGE_CAMPAIGN
"company": {
"name": "Acme Corporation"
}
}
]
}
Company List Response
In /user/companies
, permissions are also returned as bitfield integers:
{
"items": [
{
"company_id": "c193a06f-1c25-4e65-84a7-95faaae7ae7b",
"permissions": 6, // ADMINISTRATOR + MANAGE_CAMPAIGN
"company": {
"name": "Acme Corporation"
}
}
]
}
Managing API Key Permissions
For API Key Creators
- Request Access: Create an API key and select companies
- Wait for Authorization: Company administrators must authorize your key
- Check Permissions: Use
/user/companies
to see granted permissions - Request Changes: Contact company administrators for permission updates
For Company Administrators
- Review Requests: Check pending API key authorization requests
- Grant Permissions: Select appropriate permissions based on user needs
- Monitor Usage: Regularly review API key permissions and usage
- Revoke Access: Remove authorization when no longer needed
Security Best Practices
Principle of Least Privilege
- Grant only the minimum permissions required for the intended use case
- Regularly review and audit API key permissions
- Remove unused or unnecessary permissions
Permission Separation
- Use different API keys for different purposes
- Separate development and production API keys
- Limit campaign-specific keys to relevant campaigns only
Regular Audits
- Review API key permissions quarterly
- Monitor API key usage and access patterns
- Remove inactive or unused API keys
Example Permission Scenarios
Campaign Manager Role
Permissions: MANAGE_CAMPAIGN
+ REPORT
(Value: 20)
- Create and manage campaigns
- View candidate results and generate reports
- Cannot manage company users or finances
HR Administrator Role
Permissions: ADMINISTRATOR
(Value: 2)
- Manage company users and invitations
- Create and manage recruitment campaigns
- Send follow-up emails to candidates
Finance Manager Role
Permissions: FINANCE
+ REPORT
(Value: 24)
- Access billing and subscription information
- Generate financial reports
- Cannot manage campaigns or users
Administrator Permissions Management
Only users with the FOUNDER
permission can modify the permissions of an ADMINISTRATOR
. The FOUNDER
permission is automatically assigned to the person who created the company and cannot be assigned by regular administrators.
If you need to assign a new FOUNDER
for a company, at the moment it's not possible by yourself. In the meantime you can contact DeePsy's administrators through the contact form at https://deepsy.fr/contact.
Error Responses
Insufficient Permissions
{
"error": "You do not have the required permissions to access this resource",
"error_code": "INSUFFICIENT_PERMISSIONS"
}
No Company Access
{
"error": "User is not within this company",
"error_code": "USER_NOT_IN_COMPANY"
}
API Key Not Authorized
{
"error": "API key is not authorized for this company",
"error_code": "API_KEY_NOT_AUTHORIZED"
}
Related Guides
- Authentication Guide - Set up API keys and authorization
- Company Users Guide - Understand user profiles and company memberships
- Campaign Management Guide - Create and manage campaigns
- Error Handling Guide - Handle permission-related errors