PermissionContext
The PermissionContext provides application-wide access to user permissions and role-based permission checking. It automatically loads permissions from the backend when a user is authenticated and provides utilities to check if the current user has specific permissions.
Import
import { PermissionProvider, usePermissions } from '@/src/context/PermissionContext';
Provider Setup
Wrap your application (or the relevant part) with the PermissionProvider:
import { PermissionProvider } from '@/src/context/PermissionContext';
function App() {
return (
<AuthProvider>
<PermissionProvider>
<YourAppContent />
</PermissionProvider>
</AuthProvider>
);
}
The PermissionProvider must be placed inside the AuthProvider as it depends on the authenticated user.
Hook: usePermissions
The usePermissions hook provides access to the permission context. It must be used within a component that is a child of PermissionProvider.
Return Value
Array of permission codes that the current user has. Empty array if user is not authenticated.
Indicates whether permissions are currently being loaded from the backend.
hasPermission
(code: string) => boolean
Function to check if the current user has a specific permission. Returns true for admin users regardless of the permission code.
Function to manually refresh permissions from the backend. Useful after permission changes.
Usage
Basic Permission Check
import { usePermissions } from '@/src/context/PermissionContext';
function MyComponent() {
const { hasPermission, loading } = usePermissions();
if (loading) {
return <LoadingSpinner />;
}
if (!hasPermission('VIEW_REPORTS')) {
return <Text>You don't have permission to view reports</Text>;
}
return <ReportsView />;
}
Conditional Rendering
function ActionButtons() {
const { hasPermission } = usePermissions();
return (
<View>
{hasPermission('CREATE_RECORD') && (
<Button title="Create New" onPress={handleCreate} />
)}
{hasPermission('DELETE_RECORD') && (
<Button title="Delete" onPress={handleDelete} />
)}
</View>
);
}
Accessing All Permissions
function PermissionsList() {
const { permissions, loading } = usePermissions();
if (loading) {
return <Text>Loading permissions...</Text>;
}
return (
<View>
<Text>Your permissions:</Text>
{permissions.map(perm => (
<Text key={perm}>- {perm}</Text>
))}
</View>
);
}
Refreshing Permissions
function PermissionManager() {
const { refreshPermissions, loading } = usePermissions();
const handleRefresh = async () => {
try {
await refreshPermissions();
Alert.alert('Success', 'Permissions refreshed');
} catch (error) {
Alert.alert('Error', 'Failed to refresh permissions');
}
};
return (
<Button
title="Refresh Permissions"
onPress={handleRefresh}
disabled={loading}
/>
);
}
Role-Based Permission Checking
The hasPermission function includes built-in admin privilege escalation:
- Admin users: Always return
true for any permission check
- Non-admin users: Check against the permissions array loaded from the backend
From src/context/PermissionContext.tsx:50:
const hasPermission = (code: string) => {
if (user?.role === 'admin') return true;
return permissions.includes(code);
}
How It Works
- Automatic Loading: When a user is authenticated, permissions are automatically loaded from the backend via
GET /auth/permissions
- Reactive Updates: Permissions reload whenever the authenticated user changes
- Optimistic Admin Access: Admin users bypass permission checks locally, though backend validation is still the authority
- Error Handling: If permission loading fails, the permissions array is set to empty and an error is logged
API Endpoint
The context expects a backend endpoint:
GET /auth/permissions
Response: string[] - Array of permission codes
[
"VIEW_REPORTS",
"CREATE_RECORD",
"EDIT_RECORD",
"DELETE_RECORD"
]
Source Code
Location: src/context/PermissionContext.tsx:14
export function PermissionProvider({ children }: { children: React.ReactNode }) {
const { user } = useAuth();
const [permissions, setPermissions] = useState<string[]>([]);
const [loading, setLoading] = useState(true);
const loadPermissions = async () => {
if (!user) {
setPermissions([]);
setLoading(false);
return;
}
try {
const res = await apiClient.get<string[]>('/auth/permissions');
setPermissions(res.data);
} catch (error) {
console.error('Error cargando permisos', error);
setPermissions([]);
} finally {
setLoading(false);
}
};
useEffect(() => {
loadPermissions();
}, [user]);
const hasPermission = (code: string) => {
if (user?.role === 'admin') return true;
return permissions.includes(code);
}
return (
<PermissionContext.Provider value={{ permissions, loading, hasPermission, refreshPermissions: loadPermissions }}>
{children}
</PermissionContext.Provider>
);
}