Group Role Restrictions - Integration Examples
This guide provides practical integration examples for using Group Role Restrictions with JWT tokens in various frameworks and systems.
Related: See Groups Role Restriction for the complete feature documentation.
Overview
When Group Role Restrictions are configured as a Token Condition, the verification results are embedded as custom claims in the JWT access token. These claims (groupIds, rolesOfGroup, allowedGroups) can be used directly in your application for authorization decisions.
JWT Integration Pattern
The common pattern across all frameworks is:
// 1. Extract roles from JWT
const roles = jwt.claims.rolesOfGroup;
// 2. Map roles to permissions
const permissions = mapRolesToPermissions(roles);
// 3. Check permission
if (permissions.includes(requiredPermission)) {
// Allow access
} else {
// Deny access
}
Embedding rolesOfGroup in JWT tokens allows instant, secure access control without extra database lookups. It provides applications with a ready-to-use, flattened list of user permissions—enabling seamless integration with modern role-based systems that expect simple, direct role information.
Integration Examples
1. Spring Security (Java)
How it works:
- Uses flat permission strings in
@PreAuthorizeannotations - No group hierarchy - just direct permission checks
- Perfect for JWT role mapping
// Spring Security with JWT roles
@RestController
public class UserController {
@PreAuthorize("hasRole('ADMIN') or hasRole('USER_MANAGER')")
@GetMapping("/users")
public List<User> getUsers() {
return userService.getAllUsers();
}
@PreAuthorize("hasAuthority('USER_DELETE')")
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable String id) {
userService.deleteUser(id);
}
}
// JWT Role to Permission Mapping
@Component
public class JwtRoleMapper {
private final Map<String, List<String>> rolePermissions = Map.of(
"admin", Arrays.asList("USER_READ", "USER_WRITE", "USER_DELETE", "PROJECT_MANAGE"),
"developer", Arrays.asList("PROJECT_READ", "PROJECT_WRITE", "CODE_COMMIT"),
"user", Arrays.asList("PROFILE_READ", "PROFILE_WRITE")
);
public List<String> getPermissionsForRoles(List<String> roles) {
return roles.stream()
.flatMap(role -> rolePermissions.getOrDefault(role, Collections.emptyList()).stream())
.distinct()
.collect(Collectors.toList());
}
}
2. Django REST Framework (Python)
How it works:
- Uses flat permission strings in decorators
- No inheritance - just direct permission checks
- Easy JWT integration
# Django with JWT roles
from rest_framework.decorators import permission_classes
from rest_framework.permissions import BasePermission
class JwtPermission(BasePermission):
def has_permission(self, request, view):
# Extract roles from JWT token
roles = request.user.jwt_claims.get('rolesOfGroup', [])
# Map roles to permissions
permissions = self.get_permissions_for_roles(roles)
# Check if user has required permission
required_permission = getattr(view, 'required_permission', None)
return required_permission in permissions
def get_permissions_for_roles(self, roles):
role_permissions = {
'admin': ['users:read', 'users:write', 'users:delete', 'projects:manage'],
'developer': ['projects:read', 'projects:write', 'code:commit'],
'user': ['profile:read', 'profile:write']
}
permissions = []
for role in roles:
permissions.extend(role_permissions.get(role, []))
return list(set(permissions)) # Remove duplicates
# Usage in views
@permission_classes([JwtPermission])
class UserViewSet(viewsets.ModelViewSet):
required_permission = 'users:read'
def list(self, request):
# Only users with 'users:read' permission can access
return Response({'users': []})
3. Apache Shiro (Java)
How it works:
- Uses flat permission strings like
user:read,project:write - No hierarchical structure - just direct permission checks
- Perfect for JWT role mapping
// Apache Shiro with JWT roles
@Component
public class JwtRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
// Extract roles from JWT token
List<String> roles = getRolesFromJwtToken(username);
// Map roles to permissions
Set<String> permissions = mapRolesToPermissions(roles);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(new HashSet<>(roles));
info.setStringPermissions(permissions);
return info;
}
private Set<String> mapRolesToPermissions(List<String> roles) {
Map<String, List<String>> rolePermissions = Map.of(
"admin", Arrays.asList("user:read", "user:write", "user:delete", "project:manage"),
"developer", Arrays.asList("project:read", "project:write", "code:commit"),
"user", Arrays.asList("profile:read", "profile:write")
);
return roles.stream()
.flatMap(role -> rolePermissions.getOrDefault(role, Collections.emptyList()).stream())
.collect(Collectors.toSet());
}
}
4. Open Policy Agent (OPA)
How it works:
- Uses Rego policies with flat permission lists
- No hierarchical structure - just boolean permission checks
- Perfect for JWT role mapping
# OPA Policy using flattened roles
package auth
import input.jwt.claims
# Map JWT roles to permissions
permissions := {
"admin": ["users:read", "users:write", "users:delete", "projects:manage"],
"developer": ["projects:read", "projects:write", "code:commit"],
"user": ["profile:read", "profile:write"]
}
# Check if user has permission
allow {
user_roles := claims.rolesOfGroup
required_permission := input.permission
user_permissions := {p | role := user_roles[_]; p := permissions[role]}
required_permission in user_permissions
}
Using Token Claims
Extracting rolesOfGroup Claim
The rolesOfGroup claim is the most commonly used claim, providing a flattened list of all roles:
// JavaScript/Node.js
const jwt = require('jsonwebtoken');
const token = req.headers.authorization.split(' ')[1];
const decoded = jwt.decode(token);
const roles = decoded.rolesOfGroup; // ["developer", "project-manager"]
# Python
import jwt
token = request.headers.get('Authorization').split(' ')[1]
decoded = jwt.decode(token, verify=False)
roles = decoded.get('rolesOfGroup', []) # ["developer", "project-manager"]
Extracting groupIds Claim
Use groupIds when you need to know which specific groups the user belongs to:
const groupIds = decoded.groupIds; // ["eng-group", "support-group"]
Extracting allowedGroups Claim
Use allowedGroups when you need detailed group-role mappings:
const allowedGroups = decoded.allowedGroups;
// [
// { "groupId": "eng-group", "roles": ["developer"] },
// { "groupId": "support-group", "roles": ["support-agent"] }
// ]
Best Practices
- Use
rolesOfGroupfor most cases - It's the simplest and most efficient claim - Map roles to permissions - Don't check roles directly; map them to specific permissions
- Cache permission mappings - Role-to-permission mappings rarely change
- Validate token signature - Always verify JWT signature before trusting claims
- Handle missing claims gracefully - Claims may not be present if verification failed
Related Documentation
- Groups Role Restriction - Complete feature documentation
- Token Conditions and Prechecks - How token conditions work
- Groups and Roles API - API reference