The User Roles Service is a core data service responsible for storing user roles for RBAC (Role-Based Access Control), and integrating with AWS Cognito to provide a user administration API.
- Documentation
- Architecture
- Endpoints
- Deploying User Roles service in your project
- Running locally
- Linting
- Main confluence page (Liflig-internal)
The User Roles service has 2 modules:
- The
rolesmodule provides simple CRUD on user roles - The
administrationmodule integrates with Cognito (the identity provider service from AWS), to allow clients to do CRUD on users and their associated roles
When verifying a user's JWT, only the roles module is used. An important design principle here is that authentication should not be blocked when there are problems in the administration module. Therefore, the User Roles service has been designed to make the roles module independent from the administration module. For example, if the administration module is misconfigured, then the service will still start, and only the administration API will respond with 500 Internal Server Error.
| Endpoint | What |
|---|---|
| GET /api/userroles/{username} | Get roles for user |
| PUT /api/userroles/{username} | Create or update roles for user |
| DELETE /api/userroles/{username} | Delete roles for user |
| GET /api/userroles?roleName={roleName}&orgId={orgId2} | List/query user roles |
{
"username": "user123",
"roles": [
{
"applicationName": "application1",
"orgId": "orgId1",
"roleName": "orgOwner"
},
{
"applicationName": "application2",
"orgId": "orgId2",
"roleName": "orgAdmin"
},
{
"applicationName": "application2",
"orgId": "orgId3",
"roleName": "orgMember",
"roleValue": "<value>"
},
{
"roleName": "admin"
}
]
}When referring to "our identity provider" below, we mean AWS Cognito. But User Roles may be expanded in the future to support other identity providers.
The user administration API does not take responsibility for verifying that a requesting user is authorized to assign the given roles. That is the responsibility of the BFF (Backend-For-Frontend) service in your project. This is because the User Roles service does not know the content or hierarchy of roles in your project, so only a project-specific service has the knowledge to perform authorization.
| Endpoint | What | Cognito API used |
|---|---|---|
| GET /api/administration/users/{username} | Get user data from our identity provider, along with their roles | AdminGetUser |
| POST /api/administration/users | Register user in our identity provider, along with roles | AdminCreateUser |
| PUT /api/administration/users | Update existing user in our identity provider, along with their roles | AdminUpdateUserAttributes |
| DELETE /api/administration/users/{username} | Delete user in our identity provider, along with their roles | AdminDeleteUser |
| POST /api/administration/users/{username}/reset-password | Reset a user's password | AdminResetUserPassword |
| GET /api/administration/users ?limit={page size} &cursor={nextCursor from previous response} &searchString={searchString} &searchField={USERNAME | EMAIL | etc.} &orgId={role orgId} &applicationName={role applicationName} &roleName={roleName} |
List/query users from our identity provider, along with their roles. Uses cursor-based pagination: The response body includes a nextCursor field, which can be passed in the cursor query parameter to get the next page. When nextCursor is null, then there are no more users to fetch. |
ListUsers |
{
"username": "test.testesen",
"userId": "4b670e7f-0ae9-4ce8-9a8b-b27d00d2f31d",
"email": {
"value": "test@example.org",
"verified": true
},
"phoneNumber": {
"value": "12345678",
"verified": false
},
"userStatus": "CONFIRMED",
"enabled": true,
"createdAt": "2025-12-04T07:25:11Z",
"attributes": {
// Attributes are arbitrary key-value data submitted by your BFF.
// Cognito supports certain standard attributes, such as "name".
"name": "Test Testesen"
},
"roles": [
{
"applicationName": "test-application",
"orgId": "liflig",
"roleName": "admin",
"roleValue": null
}
]
}- Set up a Cognito user pool
- Deploy User Roles service, using Docker image published on GitHub, along with a Postgres database
- For the user administration module to be enabled, the service needs the following:
- Config parameter
aws.cognito.userPoolId - These permissions:
cognito-idp:AdminGetUsercognito-idp:AdminCreateUsercognito-idp:AdminUpdateUserAttributescognito-idp:AdminDeleteUsercognito-idp:AdminResetUserPasswordcognito-idp:ListUsers
- Config parameter
- Implement a "pre-token generation lambda" that fetches roles from User Roles to populate Cognito JWTs
- Implement JWT verification and role parsing for authentication and authorization in your APIs
- For the user administration module:
- Implement an API client in your BFF that calls the administration API of the User Roles service
- Your BFF should verify that the requesting user has permission to update roles. This is where you enforce your project’s hierarchy of roles (i.e., which roles are allowed to change other roles)
- Implement UI for user management
- Implement an API client in your BFF that calls the administration API of the User Roles service
For example implementations of the points above, see the Liflig-internal Confluence page.
- Start the database:
docker-compose up -d - Build and run the application
- Option 1: Run the
Main.ktfile from your IDE - Option 2: Via Maven,
./build-and-run.sh - Option 3: Package and run with the actual Docker image,
./build-and-run-docker.sh
- Option 1: Run the
- Access the service at http://localhost:8080/health
To only check linting (no tests etc):
mvn spotless:checkTo format (does not fail on lint errors):
mvn spotless:apply