User Management APIs

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:

  1. Download and unzip Roles API Basics.

    curl https://resources.learn.liferay.com/examples/liferay-z3v5.zip -O
    
    unzip liferay-z3v5.zip
    
  2. 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.

  3. 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.

  4. Use the cURL script to associate a user to a regular Role. On the command line, navigate to the curl folder. Execute the RolesAssociationUserAccount_POST_ToInstance.sh script. Replace 1234 with a regular role’s ID. Replace 5678 with a user’s ID.

    ./RolesAssociationUserAccount_POST_ToInstance.sh 1234 5678
    
  5. Navigate to Global MenuControl PanelRoles. 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.

    See that the user has been associated.

  6. The REST service can also be called using the Java client. Navigate out of the curl folder and into the java folder. Compile the source files with the following command:

    javac -classpath .:* *.java
    
  7. Run the RoleUserAssociation_POST_ToInstance.java class 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:

ArgumentsDescription
-H "Content-Type: application/json"Indicates that the request body format is JSON.
-X POSTThe 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
Note

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.

Note

The main method’s comment demonstrates running the class.

The other example Java classes are similar to this one, but call different RoleResource methods.

Important

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.

Tip

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.

Note

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

Note

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.