Roles API Basics
You can create and manage roles from the Application menu, but you can also use Liferay’s REST APIs. Call these services to manage roles.
Associate a User to a Regular Role
Start a new Liferay DXP instance by running
docker run -it -m 8g -p 8080:8080 liferay/dxp:2026.q1.9-lts
Sign in to Liferay at http://localhost:8080 using the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps:
-
Download and unzip Roles API Basics.
curl https://resources.learn.liferay.com/examples/liferay-z3v5.zip -Ounzip liferay-z3v5.zip -
Use the Users_GET_FromInstance to get a list of user IDs. Make note of the user ID you wish to associate with a regular role.
-
Use the Roles_GET_FromInstance to get a list of all role IDs. Make note of the role ID you wish to associate that is
roleType: regular. For example, the Analytics Administrator regular role type. -
Use the cURL script to associate a user to a regular Role. On the command line, navigate to the
curlfolder. Execute theRolesAssociationUserAccount_POST_ToInstance.shscript. Replace1234with a regular role’s ID. Replace5678with a user’s ID../RolesAssociationUserAccount_POST_ToInstance.sh 1234 5678 -
Navigate to Global Menu → Control Panel → Roles. Under the Regular Roles tab, click the specific role you used to a associate the user. Click the Assignees tab. See that the user has been associated with the selected role.

-
The REST service can also be called using the Java client. Navigate out of the
curlfolder and into thejavafolder. Compile the source files with the following command:javac -classpath .:* *.java -
Run the
RoleUserAssociation_POST_ToInstance.javaclass with the following command.java -classpath .:* -DroleId=1234 -DuserAccountId=5678 RoleUserAssociation_POST_ToInstance
Examine the cURL Command
The RolesAssociationUserAccount_POST_ToInstance.sh script calls the REST service with a cURL command.
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}" \
--header "Content-Type: application/json" \
--request "POST" \
--user "test@liferay.com:learn"
The command takes these arguments:
| Arguments | Description |
|---|---|
-H "Content-Type: application/json" | Indicates that the request body format is JSON. |
-X POST | The HTTP method to invoke at the specified endpoint |
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}" | The REST service endpoint |
-u "test@liferay.com:learn" | Basic authentication credentials |
Basic authentication is used here for demonstration purposes. For production, you should authorize users via OAuth2. See Using OAuth2 to Authorize Users for a sample React application that uses OAuth2.
The other cURL commands use similar JSON arguments.
Examine the Java Class
The RoleUserAssociation_POST_ToInstance.java class associates a user to a regular role by calling the RoleResource service.
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
roleResource.postRoleUserAccountAssociation(
Long.valueOf(System.getProperty("roleId")),
Long.valueOf(System.getProperty("userAccountId")));
}
This class invokes the REST service using only three lines of code:
| Line (abbreviated) | Description |
|---|---|
RoleResource.Builder builder = ... | Gets a Builder for generating an RoleResource service instance. |
RoleResource roleResource = builder.authentication(...).build(); | Specifies basic authentication and generates a RoleResource service instance. |
roleResource.postRoleUserAccountAssociation(...); | Calls the postRoleUserAccountAssociation method and passes the data to post. |
Note that the project includes the com.liferay.headless.admin.user.client.jar file as a dependency. You can find client JAR dependency information for all REST applications in the API explorer in your installation at /o/api.
The main method’s comment demonstrates running the class.
The other example Java classes are similar to this one, but call different RoleResource methods.
See RoleResource for service details.
Below are examples of calling other Role REST services using cURL and Java.
Get Roles from Instance
You can list roles by executing the following cURL or Java command.
Roles_GET_FromInstance.sh
Command:
./Roles_GET_FromInstance.sh
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles" \
--user "test@liferay.com:learn"
Roles_GET_FromInstance.java
Command:
java -classpath .:* Roles_GET_FromInstance
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
Page<Role> role = roleResource.getRolesPage(Pagination.of(1, 2));
System.out.println(role);
}
The Instance’s Roles objects appear in JSON. A space role may also carry a subtype field, described in Reading and Setting a Role’s Subtype.
Get a Role
Get a specific role with the following cURL or Java command.
Use Roles_GET_FromInstance.[java|sh] to get instance Role IDs.
Roles_GET_ById.sh
Command:
./Roles_GET_ById.sh 1234
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}" \
--user "test@liferay.com:learn"
Roles_GET_ById.java
Command:
java -classpath .:* -DroleId=1234 Roles_GET_ById
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
System.out.println(
roleResource.getRole(Long.valueOf(System.getProperty("roleId"))));
}
The Role fields appear in JSON.
Associate a User to a Site Role
You can associate a user with a specific site role. Replace 1234 with the role’s ID. Replace 5678 with your site’s ID. Replace 9012 with your user’s ID.
RolesAssociationUserAccount_POST_ToSite.sh
Command:
./RolesAssociationUserAccount_POST_ToSite.sh 1234 5678 9012
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}/site/${3}" \
--header "Content-Type: application/json" \
--request "POST" \
--user "test@liferay.com:learn"
RoleUserAssociation_POST_ToSite.java
Command:
java -classpath .:* -DroleId=1234 -DsiteId=5678 -DuserAccountId=9012 RoleUserAssociation_POST_ToSite
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
roleResource.postSiteRoleUserAccountAssociation(
Long.valueOf(System.getProperty("roleId")),
Long.valueOf(System.getProperty("userAccountId")),
Long.valueOf(System.getProperty("siteId")));
}
Associate a User to a Organization Role
You can associate a user with a specific organization role. Replace 1234 with your organization’s ID. Replace 5678 with your role’s ID. Replace 9012 with your user’s ID.
RolesAssociationUserAccount_POST_ToOrganization.sh
Command:
./RolesAssociationUserAccount_POST_ToOrganization.sh 1234 5678 9012
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}/organization/${3}" \
--header "Content-Type: application/json" \
--request "POST" \
--user "test@liferay.com:learn"
RoleUserAssociation_POST_ToOrganization.java
Command:
java -classpath .:* -DorganizationId=1234 -DroleId=5678 -DuserAccountId=9012 RoleUserAssociation_POST_ToOrganization
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
roleResource.postOrganizationRoleUserAccountAssociation(
Long.valueOf(System.getProperty("roleId")),
Long.valueOf(System.getProperty("userAccountId")),
Long.valueOf(System.getProperty("organizationId")));
}
Remove Regular Role Association
Remove a regular role association from a specific user. Replace 1234 with the role’s ID. Replace 5678 with your user’s ID.
RolesAssociationUserAccount_DELETE_FromInstance.sh
Command:
./RolesAssociationUserAccount_DELETE_FromInstance.sh 1234 5678
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}" \
--header "Content-Type: application/json" \
--request "DELETE" \
--user "test@liferay.com:learn"
RoleUserAssociation_DELETE_FromInstance.java
Command
java -classpath .:* -DroleId=1234 -DuserAccountId=5678 RoleUserAssociation_DELETE_FromInstance
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
roleResource.deleteRoleUserAccountAssociation(
Long.valueOf(System.getProperty("roleId")),
Long.valueOf(System.getProperty("userAccountId")));
}
Remove Site Role Association
Remove a site role association from a specific user. Replace 1234 with the role’s ID. Replace 5678 with your site’s ID. Replace 9012 with your user’s ID.
RolesAssociationUserAccount_DELETE_FromSite.sh
Command:
./RolesAssociationUserAccount_DELETE_FromSite.sh 1234 5678 9012
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}/site/${3}" \
--header "Content-Type: application/json" \
--request "DELETE" \
--user "test@liferay.com:learn"
RoleUserAssociation_DELETE_FromSite.java
Command
java -classpath .:* -DroleId=1234 -DsiteId=5678 -DuserAccountId=9012 RoleUserAssociation_DELETE_FromSite
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
roleResource.deleteSiteRoleUserAccountAssociation(
Long.valueOf(System.getProperty("roleId")),
Long.valueOf(System.getProperty("userAccountId")),
Long.valueOf(System.getProperty("siteId")));
}
Remove Organization Role Association
Remove an organization role association from a specific user. Replace 1234 with the organization’s ID. Replace 5678 with your role’s ID. Replace 9012 with your user’s ID.
RolesAssociationUserAccount_DELETE_FromOrganization.sh
Command:
./RolesAssociationUserAccount_DELETE_FromOrganization.sh 1234 5678 9012
Code:
curl \
"http://localhost:8080/o/headless-admin-user/v1.0/roles/${1}/association/user-account/${2}/organization/${3}" \
--header "Content-Type: application/json" \
--request "DELETE" \
--user "test@liferay.com:learn"
RoleUserAssociation_DELETE_FromOrganization.java
Command
java -classpath .:* -DorganizationId=1234 -DroleId=5678 -DuserAccountId=9012 RoleUserAssociation_DELETE_FromOrganization
Code:
public static void main(String[] args) throws Exception {
RoleResource.Builder builder = RoleResource.builder();
RoleResource roleResource = builder.authentication(
"test@liferay.com", "learn"
).build();
roleResource.deleteOrganizationRoleUserAccountAssociation(
Long.valueOf(System.getProperty("roleId")),
Long.valueOf(System.getProperty("userAccountId")),
Long.valueOf(System.getProperty("organizationId")));
}
The API Explorer shows all of the Role services and schemas and has an interface to try out each service.
On Liferay DXP 2024.Q4+/Portal GA129+, you can use external reference codes to GET/PUT/PATCH/DELETE roles.
Reading and Setting a Role’s Subtype
The subtype field is available on Liferay DXP 2026.Q3+.
In the API, the Space Roles type is roleType: depot. The name depot is the platform’s internal name for the role type covering spaces, asset libraries, projects, and design libraries. A role of that type can carry a subtype field that ties it to one of those contexts. The field is both readable and writable. Its values are space, project, and design-library.
For a role with no subtype, the response omits the field instead of returning it empty. It is absent for the out-of-the-box space roles and for any custom role created before subtypes existed. When Liferay DXP filters, a null subtype counts as space.
Set a subtype when you create a role:
curl -X POST "http://localhost:8080/o/headless-admin-user/v1.0/roles" \
-H "Content-Type: application/json" \
-u "test@liferay.com:learn" \
-d '{"name": "Project Reviewer", "roleType": "depot", "subtype": "project"}'
A successful call returns 201 Created with the new role. The response includes the id the next request needs. Confirm the value with GET /o/headless-admin-user/v1.0/roles/{roleId}, whose response includes "subtype": "project".
A PATCH to the same path changes a subtype. Both PATCH and PUT keep the stored value when the request omits subtype or sends it as null. That matters because a role read back from the API arrives with subtype set to null. Send an empty string to clear a subtype.
Liferay DXP validates the subtype in the service layer, so the same rules apply to the Roles application and to API calls. The space value is always accepted. Sending subtype: "project" requires the Content Marketing Platform (CMP) release feature flag (LPD-58677), and design-library requires the Design Libraries release feature flag (LPD-57283). Sending a value whose flag is disabled returns 400 Bad Request. The response body carries "title": "The role subtype is invalid". The generated Java client raises Problem.ProblemException; read the message from its Problem. An in-JVM caller of RoleService gets a RoleSubtypeException instead. A 400 on one of the three documented values means that value’s flag is disabled. See Feature Flags.
Filter a role listing by subtype with an OData expression:
curl "http://localhost:8080/o/headless-admin-user/v1.0/roles" \
--get \
--data-urlencode "filter=subtype eq 'project'" \
-u "test@liferay.com:learn"
The filter matches stored values only. A role with no subtype is not indexed under subtype at all: subtype eq 'space' returns neither the out-of-the-box space roles nor any custom role created before subtypes existed. To reach every space role, list them by type with types=5 and apply the null-means-space rule in your client.
A role’s name is independent of the title the Roles application displays. The application lists Space Administrator, but that same role returns name: "Asset Library Administrator". Only the display title is remapped. Match on name rather than on the displayed title. The same response carries the displayed title as name_i18n, a map of language ID to title ({"en-US": "Space Administrator"}).
The Role endpoints in this article return every space role. Among the role listings, GET /o/headless-asset-library/v1.0/asset-libraries/{assetLibraryExternalReferenceCode}/roles narrows the list by context when the Depot Role Scoping release feature flag (LPD-96750) is enabled. That endpoint returns a different Role schema: it omits subtype and reports roleType as the integer 5 rather than the string depot. Read a role’s subtype from the headless-admin-user endpoints above. For the filtering rules, see Space Role Subtypes.
Role Management via Batch Engine
The Roles API supports batch export and import for migrating roles across Liferay instances, using the com.liferay.headless.admin.user.dto.v1_0.Role entity class name.
For details on using the Batch Engine, see Exporting and Importing Data using the Batch Engine API.