This article provides steps to create a CSV report of users and their registered devices using the API and Postman.
- Okta Identity Engine (OIE)
- API
- Devices
- Okta Reports
To generate the report, an API call must be configured and executed in Postman, followed by a script that processes the response data.
- Configure the API request. There are two methods to create the GET call:
- Method 1: Direct Creation
- Use the GET method on the following endpoint:
https://<yourdomain>.okta.com/api/v1/devices?expand=userSummary.
- Use the GET method on the following endpoint:
- Method 2: Using Postman Collection
- Import the Devices collection from the Okta Postman Collections page.
- Duplicate the GET all devices request.
- Modify the request URL from
{{url}}/api/v1/devices to {{url}}/api/v1/devices?expand=userSummary.
- Method 1: Direct Creation
- Under Headers, add the following key-value pairs:
- ACCEPT: application/json
- Content-Type: application/json
- Authorization:
SSWS {{apikey}}. NOTE: The{{apikey}}value is the token generated in the Admin Console under Security > API > Tokens.
- The API call returns a raw JavaScript Object Notation (JSON) body response containing details for all devices and their associated users.
- To format this JSON response into a filtered table, navigate to the Scripts tab in Postman and create a post-response script.
- Send the API to generate the report. The CSV table is in the response Body under the Visualize tab.
Example of a post-response script:
const template = `
<style>
body { font-family: sans-serif; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; vertical-align: top; }
th { background-color: #f2f2f2; }
tr:nth-child(even) { background-color: #f9f9f9; }
pre { margin: 0; background-color: #eee; padding: 5px; border-radius: 4px; white-space: pre-wrap; word-break: break-all; }
</style>
<h2>Filtered Device Report</h2>
<table>
<thead>
<tr>
<th>User Login</th>
<th>Device ID</th>
<th>Device Profile (JSON)</th>
</tr>
</thead>
<tbody>
{{#each devices}}
<tr>
<td>{{userLogin}}</td>
<td>{{id}}</td>
<td><pre><code>{{profile}}</code></pre></td>
</tr>
{{/each}}
</tbody>
</table>
`;
if (pm.response.code === 200) {
console.log("Request was successful (200 OK). Processing response...");
const responseData = pm.response.json();
if (Array.isArray(responseData) && responseData.length > 0) {
console.log("Found " + responseData.length + " devices in this response page.");
const flattenedData = responseData.flatMap(device => {
const users = device._embedded?.users || [];
if (users.length === 0) {
return [{
id: device.id,
profile: JSON.stringify(device.profile, null, 2),
userLogin: "N/A"
}];
}
return users.map(userEntry => {
return {
id: device.id,
profile: JSON.stringify(device.profile, null, 2),
userLogin: userEntry.user?.profile?.login || "N/A"
};
});
});
console.log("Data successfully flattened. Total rows created:", flattenedData.length);
console.log("First data object:", flattenedData[0]);
pm.visualizer.set(template, { devices: flattenedData });
console.log("Visualizer data set. Click the 'Visualize' tab to see the report.");
} else {
console.warn("Response was successful, but contained no device data.");
pm.visualizer.set("<h3>Response is empty. No devices found on this page.</h3>");
}
} else {
console.error("API request failed with status code: " + pm.response.code);
console.error("Response Body:", pm.response.text());
pm.visualizer.set(`
<h2 style="color:red;">API Request Failed</h2>
<p><b>Status:</b> ${pm.response.code} ${pm.response.status}</p>
<p>Check the Postman Console for more details.</p>
`);
}
NOTE: If a rate limit error occurs, use the Postman runner and stop at the device rate limit specified in the tenant. Alternatively, use pagination by following this pagination guide.
