Skip to content

Introduce New Device Management API Endpoint - #1150

Open
kaviska wants to merge 4 commits into
wso2:masterfrom
kaviska:device-mgt-api
Open

Introduce New Device Management API Endpoint#1150
kaviska wants to merge 4 commits into
wso2:masterfrom
kaviska:device-mgt-api

Conversation

@kaviska

@kaviska kaviska commented Jul 17, 2026

Copy link
Copy Markdown

Purpose

This PR adds a new Device Management REST API (/api/server/v1/devices) to the Identity Server API layer. It exposes the underlying DeviceManagementService over HTTP, allowing tenant administrators to manage registered devices through the Admin API.

Goals

The API provides the following device management operations:

  • List registered devices with pagination (limit and offset).
  • Filter devices by the owning user (userId) while preserving pagination and total result counts.
  • Retrieve a device by its ID.
  • Rename a device.
  • Delete a registered device.

Implementation

A new Maven component, org.wso2.carbon.identity.api.server.device.mgt, has been introduced following the existing API Server structure.

Modules

.common

  • Defines shared constants and API error codes.
  • Provides DeviceMgtServiceHolder for accessing the DeviceManagementService OSGi service.

.v1

  • Contains the versioned REST API implementation.
  • device-mgt.yaml defines the OpenAPI specification, with API models and interfaces generated from it.
  • DevicesApiServiceImpl implements the JAX-RS endpoints.
  • DeviceManagementApiService contains the API logic, including request validation, tenant resolution, and delegation to DeviceManagementService.
  • DeviceServiceFactory initializes and provides the backend service instance.

User stories

  • As a tenant administrator, I can view all registered devices in my tenant with pagination.
  • As a tenant administrator, I can view all devices registered by a specific user, including inactive devices.
  • As a tenant administrator, I can retrieve, rename, or delete a device by its ID.

Developer Checklist (Mandatory)

  • Complete the Developer Checklist in the related product-is issue to capture any behavioral changes or migration impacts.

Release note

N/A

Documentation

N/A

Training

N/A

Certification

N/A

Marketing

N/A

Automation tests

N/A

Security checks

  • Followed the WSO2 Secure Engineering Guidelines: Yes
  • Ran the FindSecurityBugs plugin and verified the report:
  • Confirmed that no keys, passwords, tokens, or other secrets are included: Yes

Samples

N/A

Related PRs

wso2/carbon-identity-framework#8202

Migrations

N/A – This introduces a new API and does not require any migration.

Test environment

N/A

Learning

N/A

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary

  • Added the Device Management REST API at /api/server/v1/devices.
  • Added endpoints to list, filter, retrieve, rename, and delete devices.
  • Implemented pagination, total counts, tenant resolution, request validation, and pagination links that preserve userId filters.
  • Added OpenAPI definitions, response models, error handling, and service integration with DeviceManagementService.
  • Added shared constants, service access utilities, Maven modules, and required dependency configuration.
  • Fixed registeredAt timestamp serialization and aligned dependency version management.

Walkthrough

Adds a new Maven device-management module with shared constants, error definitions, and OSGi service access. Defines an OpenAPI 3.0 contract for listing, retrieving, renaming, and deleting devices, including pagination, security schemes, schemas, and generated CXF sources. Adds REST delegation and a core service that validates requests, applies tenant scoping, maps device data, builds pagination links, and converts backend exceptions into API errors.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DevicesApiServiceImpl
  participant DeviceManagementApiService
  participant DeviceManagementService

  Client->>DevicesApiServiceImpl: Request device operation
  DevicesApiServiceImpl->>DeviceManagementApiService: Delegate request
  DeviceManagementApiService->>DeviceManagementService: Query or modify device
  DeviceManagementService-->>DeviceManagementApiService: Return result or exception
  DeviceManagementApiService-->>DevicesApiServiceImpl: Return API model or APIError
  DevicesApiServiceImpl-->>Client: Return HTTP response
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and directly matches the new device management API work, though it slightly understates that multiple endpoints were added.
Description check ✅ Passed The PR description covers the required sections and is mostly complete, with only minor gaps in the security checks and automation test details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/v1/core/DeviceManagementApiService.java`:
- Around line 134-170: The pagination logic in the previous-link path can
overflow and recursively traverse many pages. Update the relevant calculations
in the link-building method and calculateOffsetForPreviousLink to use long
arithmetic for offset, limit, and total comparisons, and replace recursive
page-by-page stepping with a bounded or constant-time calculation that returns a
valid previous offset. Preserve existing link behavior, including the
zero-offset branch and valid limit handling.

In
`@components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/resources/device-mgt.yaml`:
- Around line 30-32: Update the OpenAPI security configuration in the device
management specification to declare the documented internal_device_mgt_* OAuth2
scopes instead of an empty scope list, then add the applicable OAuth2 scope
requirement to each affected operation, including the operations in the
referenced range. Keep BasicAuth unchanged and align every operation’s required
scope with its named permission.
- Around line 43-81: Update the pagination parameters in the OpenAPI schema by
adding maximum: 100 to the limit schema, matching
Constants.ErrorMessage.ERROR_CODE_INVALID_PAGINATION validation. Add a 400
response to the operation’s responses, documenting the invalid-pagination error
using the existing Error schema.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 51d36a2e-8df5-4d22-b02c-9d42bae2870e

📥 Commits

Reviewing files that changed from the base of the PR and between bb56735 and af8ec24.

⛔ Files ignored due to path filters (8)
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/DevicesApi.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/DevicesApiService.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/factories/DevicesApiServiceFactory.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/model/DeviceListLink.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/model/DeviceListResponse.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/model/DevicePatchRequest.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/model/DeviceResponse.java is excluded by !**/gen/**
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/gen/java/org/wso2/carbon/identity/api/server/device/mgt/v1/model/Error.java is excluded by !**/gen/**
📒 Files selected for processing (11)
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.common/pom.xml
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.common/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/common/Constants.java
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.common/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/common/DeviceMgtServiceHolder.java
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/pom.xml
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/v1/core/DeviceManagementApiService.java
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/v1/factories/DeviceServiceFactory.java
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/v1/function/DeviceResponseBuilder.java
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/v1/impl/DevicesApiServiceImpl.java
  • components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/resources/device-mgt.yaml
  • components/org.wso2.carbon.identity.api.server.device.mgt/pom.xml
  • pom.xml

Comment on lines +134 to +170
if ((offset + limit) < totalResults) {
links.add(buildPageLink(baseUrl, Constants.PAGE_LINK_REL_NEXT, offset + limit, limit, userId));
}

/*
Previous link.
Previous link matters only if offset is greater than 0.
*/
if (offset > 0) {
if ((offset - limit) >= 0) { // A previous page of size 'limit' exists.
links.add(buildPageLink(baseUrl, Constants.PAGE_LINK_REL_PREVIOUS,
calculateOffsetForPreviousLink(offset, limit, totalResults), limit, userId));
} else { // A previous page exists but it's size is less than the specified limit.
links.add(buildPageLink(baseUrl, Constants.PAGE_LINK_REL_PREVIOUS, 0, offset, userId));
}
}

return links;
}

private DeviceListLink buildPageLink(String baseUrl, String rel, int offset, int limit, String userId) {

String query = StringUtils.isNotBlank(userId)
? String.format(Constants.PAGINATION_WITH_USER_ID_LINK_FORMAT, offset, limit, userId)
: String.format(Constants.PAGINATION_LINK_FORMAT, offset, limit);
return new DeviceListLink().rel(rel).href(ContextLoader.buildURIForBody(baseUrl + query).toString());
}

private int calculateOffsetForPreviousLink(int offset, int limit, int total) {

int newOffset = offset - limit;
if (newOffset < total) {
return newOffset;
}

// If offset is greater than total, go back by the chunks of limit until a proper page is found.
return calculateOffsetForPreviousLink(newOffset, limit, total);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Avoid overflow and recursive previous-link calculation.

Line 134 can overflow for large valid offsets, and Lines 162-170 recursively step backward one page at a time. Use long for offset arithmetic and a bounded or constant-time previous-offset calculation so pagination links remain valid for large inputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/java/org/wso2/carbon/identity/api/server/device/mgt/v1/core/DeviceManagementApiService.java`
around lines 134 - 170, The pagination logic in the previous-link path can
overflow and recursively traverse many pages. Update the relevant calculations
in the link-building method and calculateOffsetForPreviousLink to use long
arithmetic for offset, limit, and total comparisons, and replace recursive
page-by-page stepping with a bounded or constant-time calculation that returns a
valid previous offset. Preserve existing link behavior, including the
zero-offset branch and valid limit handling.

Comment on lines +30 to +32
security:
- OAuth2: []
- BasicAuth: []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Declare and require the documented OAuth2 permissions.

The global OAuth2 requirement uses an empty scope list, and the declared scope names do not match the internal_device_mgt_* permissions named by the operations. Define those permission names as scopes and require the applicable scope on each operation.

Also applies to: 212-221

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/resources/device-mgt.yaml`
around lines 30 - 32, Update the OpenAPI security configuration in the device
management specification to declare the documented internal_device_mgt_* OAuth2
scopes instead of an empty scope list, then add the applicable OAuth2 scope
requirement to each affected operation, including the operations in the
referenced range. Keep BasicAuth unchanged and align every operation’s required
scope with its named permission.

Comment on lines +43 to +81
- name: limit
in: query
description: Maximum number of records to return.
required: false
schema:
type: integer
minimum: 1
default: 30
- name: offset
in: query
description: Number of records to skip for pagination.
required: false
schema:
type: integer
minimum: 0
default: 0
- name: userId
in: query
description: Filter devices by the ID of the user who registered them. Returns devices of any status. Pagination applies as usual.
required: false
schema:
type: string
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/DeviceListResponse'
'401':
description: Unauthorized
'403':
description: Forbidden
'500':
description: Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Align the pagination contract with server validation.

Constants.ErrorMessage.ERROR_CODE_INVALID_PAGINATION limits limit to 1–100, but this schema has no maximum, and the operation omits its 400 error response. Add maximum: 100 and document the invalid-pagination response.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@components/org.wso2.carbon.identity.api.server.device.mgt/org.wso2.carbon.identity.api.server.device.mgt.v1/src/main/resources/device-mgt.yaml`
around lines 43 - 81, Update the pagination parameters in the OpenAPI schema by
adding maximum: 100 to the limit schema, matching
Constants.ErrorMessage.ERROR_CODE_INVALID_PAGINATION validation. Add a 400
response to the operation’s responses, documenting the invalid-pagination error
using the existing Error schema.

@Thisara-Welmilla

Copy link
Copy Markdown
Contributor

Why we need this functionality List registered devices with pagination (limit and offset)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants